Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 22 Jun 2006 22:07:59 +0000 (15:07 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 22 Jun 2006 22:07:59 +0000 (15:07 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6: (27 commits)
  [PATCH] PCI: nVidia quirk to make AER PCI-E extended capability visible
  [PATCH] PCI: fix issues with extended conf space when MMCONFIG disabled because of e820
  [PATCH] PCI: Bus Parity Status sysfs interface
  [PATCH] PCI: fix memory leak in MMCONFIG error path
  [PATCH] PCI: fix error with pci_get_device() call in the mpc85xx driver
  [PATCH] PCI: MSI-K8T-Neo2-Fir: run only where needed
  [PATCH] PCI: fix race with pci_walk_bus and pci_destroy_dev
  [PATCH] PCI: clean up pci documentation to be more specific
  [PATCH] PCI: remove unneeded msi code
  [PATCH] PCI: don't move ioapics below PCI bridge
  [PATCH] PCI: cleanup unused variable about msi driver
  [PATCH] PCI: disable msi mode in pci_disable_device
  [PATCH] PCI: Allow MSI to work on kexec kernel
  [PATCH] PCI: AMD 8131 MSI quirk called too late, bus_flags not inherited ?
  [PATCH] PCI: Move various PCI IDs to header file
  [PATCH] PCI Bus Parity Status-broken hardware attribute, EDAC foundation
  [PATCH] PCI: i386/x86_84: disable PCI resource decode on device disable
  [PATCH] PCI ACPI: Rename the functions to avoid multiple instances.
  [PATCH] PCI: don't enable device if already enabled
  [PATCH] PCI: Add a "enable" sysfs attribute to the pci devices to allow userspace (Xorg) to enable devices without doing foul direct access
  ...

547 files changed:
Documentation/ABI/README [new file with mode: 0644]
Documentation/ABI/obsolete/devfs [new file with mode: 0644]
Documentation/ABI/stable/syscalls [new file with mode: 0644]
Documentation/ABI/stable/sysfs-module [new file with mode: 0644]
Documentation/ABI/testing/sysfs-class [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices [new file with mode: 0644]
Documentation/isdn/README.gigaset
Documentation/keys.txt
Documentation/power/devices.txt
Documentation/power/swsusp.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
Documentation/usb/usbmon.txt
MAINTAINERS
arch/powerpc/boot/Makefile
arch/powerpc/sysdev/fsl_soc.c
arch/ppc/boot/lib/Makefile
arch/ppc/syslib/mpc83xx_devices.c
arch/sparc/kernel/setup.c
arch/um/kernel/time_kern.c
arch/x86_64/Kconfig
arch/xtensa/boot/lib/Makefile
block/genhd.c
drivers/base/Kconfig
drivers/base/Makefile
drivers/base/attribute_container.c
drivers/base/base.h
drivers/base/bus.c
drivers/base/class.c
drivers/base/core.c
drivers/base/firmware_class.c
drivers/base/hypervisor.c [new file with mode: 0644]
drivers/base/init.c
drivers/base/isa.c [new file with mode: 0644]
drivers/base/platform.c
drivers/base/power/Makefile
drivers/base/power/suspend.c
drivers/base/sys.c
drivers/block/cciss.c
drivers/block/ub.c
drivers/char/agp/Kconfig
drivers/char/tty_io.c
drivers/isdn/gigaset/common.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/gigaset/interface.c
drivers/isdn/gigaset/proc.c
drivers/media/video/usbvideo/konicawc.c
drivers/net/myri10ge/myri10ge.c
drivers/usb/Makefile
drivers/usb/atm/usbatm.c
drivers/usb/atm/xusbatm.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/core/Makefile
drivers/usb/core/devio.c
drivers/usb/core/endpoint.c [new file with mode: 0644]
drivers/usb/core/file.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/sysfs.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/gadget/ether.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/rndis.c
drivers/usb/gadget/rndis.h
drivers/usb/gadget/serial.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/sl811_cs.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-hub.c
drivers/usb/host/uhci-q.c
drivers/usb/input/acecad.c
drivers/usb/input/aiptek.c
drivers/usb/input/appletouch.c
drivers/usb/input/ati_remote.c
drivers/usb/input/ati_remote2.c
drivers/usb/input/hid-core.c
drivers/usb/input/hid-input.c
drivers/usb/input/hid.h
drivers/usb/input/itmtouch.c
drivers/usb/input/kbtab.c
drivers/usb/input/keyspan_remote.c
drivers/usb/input/mtouchusb.c
drivers/usb/input/powermate.c
drivers/usb/input/touchkitusb.c
drivers/usb/input/usbkbd.c
drivers/usb/input/usbmouse.c
drivers/usb/input/usbtouchscreen.c
drivers/usb/input/wacom.c
drivers/usb/input/xpad.c
drivers/usb/input/yealink.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/appledisplay.c [new file with mode: 0644]
drivers/usb/misc/cy7c63.c [new file with mode: 0644]
drivers/usb/misc/phidgetkit.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/usb/misc/sisusbvga/sisusb_init.c
drivers/usb/misc/sisusbvga/sisusb_init.h
drivers/usb/misc/sisusbvga/sisusb_struct.h
drivers/usb/misc/usbtest.c
drivers/usb/mon/mon_dma.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_stat.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/net/asix.c
drivers/usb/net/cdc_ether.c
drivers/usb/net/pegasus.c
drivers/usb/net/rndis_host.c
drivers/usb/net/zaurus.c
drivers/usb/serial/Kconfig
drivers/usb/serial/airprime.c
drivers/usb/serial/console.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/omninet.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb-serial.h
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/shuttle_usbat.h
drivers/usb/storage/transport.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/video/console/mdacon.c
drivers/video/console/vgacon.c
drivers/video/vga16fb.c
fs/binfmt_elf.c
fs/binfmt_misc.c
fs/block_dev.c
fs/dcache.c
fs/exec.c
fs/locks.c
fs/ntfs/file.c
fs/partitions/check.c
fs/super.c
fs/xfs/Kconfig
fs/xfs/Makefile-linux-2.6
fs/xfs/linux-2.6/kmem.h
fs/xfs/linux-2.6/mrlock.h
fs/xfs/linux-2.6/sema.h
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_aops.h
fs/xfs/linux-2.6/xfs_export.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_fs_subr.c
fs/xfs/linux-2.6/xfs_globals.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_ioctl32.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_lrw.c
fs/xfs/linux-2.6/xfs_lrw.h
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_super.h
fs/xfs/linux-2.6/xfs_sysctl.c
fs/xfs/linux-2.6/xfs_sysctl.h
fs/xfs/linux-2.6/xfs_vfs.c
fs/xfs/linux-2.6/xfs_vfs.h
fs/xfs/linux-2.6/xfs_vnode.c
fs/xfs/linux-2.6/xfs_vnode.h
fs/xfs/quota/xfs_dquot.c
fs/xfs/quota/xfs_dquot.h
fs/xfs/quota/xfs_dquot_item.c
fs/xfs/quota/xfs_qm.c
fs/xfs/quota/xfs_qm_bhv.c
fs/xfs/quota/xfs_qm_stats.c
fs/xfs/quota/xfs_qm_syscalls.c
fs/xfs/quota/xfs_trans_dquot.c
fs/xfs/support/debug.c
fs/xfs/support/debug.h
fs/xfs/xfs_acl.c
fs/xfs/xfs_acl.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_alloc_btree.c
fs/xfs/xfs_attr.c
fs/xfs/xfs_attr.h
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_bmap_btree.c
fs/xfs/xfs_btree.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_cap.h
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_da_btree.h
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_dfrag.h
fs/xfs/xfs_dinode.h
fs/xfs/xfs_dir.c [deleted file]
fs/xfs/xfs_dir.h [deleted file]
fs/xfs/xfs_dir2.c
fs/xfs/xfs_dir2.h
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_dir2_data.c
fs/xfs/xfs_dir2_data.h
fs/xfs/xfs_dir2_leaf.c
fs/xfs/xfs_dir2_node.c
fs/xfs/xfs_dir2_sf.c
fs/xfs/xfs_dir2_trace.c
fs/xfs/xfs_dir_leaf.c [deleted file]
fs/xfs/xfs_dir_leaf.h [deleted file]
fs/xfs/xfs_dir_sf.h [deleted file]
fs/xfs/xfs_dmapi.h
fs/xfs/xfs_dmops.c
fs/xfs/xfs_error.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_extfree_item.h
fs/xfs/xfs_fs.h
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_ialloc_btree.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_inode_item.h
fs/xfs/xfs_iocore.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_itable.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qmops.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_rename.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rw.c
fs/xfs/xfs_rw.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_extfree.c
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_trans_item.c
fs/xfs/xfs_trans_space.h
fs/xfs/xfs_utils.c
fs/xfs/xfs_utils.h
fs/xfs/xfs_vfsops.c
fs/xfs/xfs_vnodeops.c
include/asm-alpha/vga.h
include/asm-arm/vga.h
include/asm-i386/vga.h
include/asm-ia64/vga.h
include/asm-m32r/vga.h
include/asm-mips/vga.h
include/asm-powerpc/vga.h
include/asm-sparc64/vga.h
include/asm-x86_64/vga.h
include/asm-xtensa/vga.h
include/linux/dcache.h
include/linux/device.h
include/linux/fs.h
include/linux/isa.h [new file with mode: 0644]
include/linux/key.h
include/linux/kobject.h
include/linux/security.h
include/linux/sysdev.h
include/linux/tty.h
include/linux/usb.h
include/linux/usb/cdc.h [moved from include/linux/usb_cdc.h with 100% similarity]
include/linux/usb/input.h [moved from include/linux/usb_input.h with 100% similarity]
include/linux/usb/isp116x.h [moved from include/linux/usb_isp116x.h with 100% similarity]
include/linux/usb/sl811.h [moved from include/linux/usb_sl811.h with 71% similarity]
include/linux/zconf.h
include/linux/zlib.h
include/linux/zutil.h
include/sound/ac97_codec.h
include/sound/asequencer.h
include/sound/asound.h
include/sound/core.h
include/sound/emu10k1.h
include/sound/info.h
include/sound/mpu401.h
include/sound/pcm.h
include/sound/pcm_params.h
include/sound/rawmidi.h
include/sound/version.h
kernel/power/main.c
kernel/sys.c
kernel/user.c
lib/kobject.c
lib/zlib_deflate/deflate.c
lib/zlib_deflate/deflate_syms.c
lib/zlib_inflate/Makefile
lib/zlib_inflate/infblock.c [deleted file]
lib/zlib_inflate/infblock.h [deleted file]
lib/zlib_inflate/infcodes.c [deleted file]
lib/zlib_inflate/infcodes.h [deleted file]
lib/zlib_inflate/inffast.c
lib/zlib_inflate/inffast.h
lib/zlib_inflate/inffixed.h [new file with mode: 0644]
lib/zlib_inflate/inflate.c
lib/zlib_inflate/inflate.h [new file with mode: 0644]
lib/zlib_inflate/inflate_syms.c
lib/zlib_inflate/inflate_sync.c [deleted file]
lib/zlib_inflate/inftrees.c
lib/zlib_inflate/inftrees.h
lib/zlib_inflate/infutil.c [deleted file]
lib/zlib_inflate/infutil.h
security/dummy.c
security/keys/key.c
security/keys/keyring.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/selinux/hooks.c
security/selinux/include/av_perm_to_string.h
security/selinux/include/av_permissions.h
security/selinux/include/class_to_string.h
security/selinux/include/flask.h
security/selinux/include/objsec.h
sound/Kconfig
sound/Makefile
sound/aoa/Kconfig [new file with mode: 0644]
sound/aoa/Makefile [new file with mode: 0644]
sound/aoa/aoa-gpio.h [new file with mode: 0644]
sound/aoa/aoa.h [new file with mode: 0644]
sound/aoa/codecs/Kconfig [new file with mode: 0644]
sound/aoa/codecs/Makefile [new file with mode: 0644]
sound/aoa/codecs/snd-aoa-codec-onyx.c [new file with mode: 0644]
sound/aoa/codecs/snd-aoa-codec-onyx.h [new file with mode: 0644]
sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h [new file with mode: 0644]
sound/aoa/codecs/snd-aoa-codec-tas.c [new file with mode: 0644]
sound/aoa/codecs/snd-aoa-codec-tas.h [new file with mode: 0644]
sound/aoa/codecs/snd-aoa-codec-toonie.c [new file with mode: 0644]
sound/aoa/core/Makefile [new file with mode: 0644]
sound/aoa/core/snd-aoa-alsa.c [new file with mode: 0644]
sound/aoa/core/snd-aoa-alsa.h [new file with mode: 0644]
sound/aoa/core/snd-aoa-core.c [new file with mode: 0644]
sound/aoa/core/snd-aoa-gpio-feature.c [new file with mode: 0644]
sound/aoa/core/snd-aoa-gpio-pmf.c [new file with mode: 0644]
sound/aoa/fabrics/Kconfig [new file with mode: 0644]
sound/aoa/fabrics/Makefile [new file with mode: 0644]
sound/aoa/fabrics/snd-aoa-fabric-layout.c [new file with mode: 0644]
sound/aoa/soundbus/Kconfig [new file with mode: 0644]
sound/aoa/soundbus/Makefile [new file with mode: 0644]
sound/aoa/soundbus/core.c [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/Makefile [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/i2sbus-control.c [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/i2sbus-control.h [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/i2sbus-core.c [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/i2sbus-interface.h [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/i2sbus-pcm.c [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/i2sbus.h [new file with mode: 0644]
sound/aoa/soundbus/soundbus.h [new file with mode: 0644]
sound/aoa/soundbus/sysfs.c [new file with mode: 0644]
sound/arm/sa11xx-uda1341.c
sound/core/control.c
sound/core/device.c
sound/core/hwdep.c
sound/core/info.c
sound/core/info_oss.c
sound/core/init.c
sound/core/isadma.c
sound/core/memory.c
sound/core/misc.c
sound/core/oss/mixer_oss.c
sound/core/oss/pcm_oss.c
sound/core/pcm.c
sound/core/pcm_compat.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_misc.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/seq/oss/seq_oss.c
sound/core/seq/seq.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_device.c
sound/core/seq/seq_dummy.c
sound/core/seq/seq_info.c
sound/core/seq/seq_lock.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_virmidi.c
sound/core/sound.c
sound/core/sound_oss.c
sound/core/timer.c
sound/drivers/dummy.c
sound/drivers/mpu401/mpu401.c
sound/drivers/mpu401/mpu401_uart.c
sound/drivers/mtpav.c
sound/drivers/opl3/opl3_lib.c
sound/drivers/opl3/opl3_oss.c
sound/drivers/opl3/opl3_seq.c
sound/drivers/opl3/opl3_synth.c
sound/drivers/opl4/opl4_lib.c
sound/drivers/opl4/opl4_seq.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/drivers/vx/vx_core.c
sound/drivers/vx/vx_hwdep.c
sound/i2c/i2c.c
sound/i2c/l3/uda1341.c
sound/isa/gus/gus_irq.c
sound/isa/gus/gus_mem.c
sound/isa/gus/gus_synth.c
sound/isa/gus/interwave.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/sb/emu8000.c
sound/isa/sb/emu8000_patch.c
sound/isa/sb/sb16.c
sound/isa/sb/sb16_csp.c
sound/isa/sb/sb8_midi.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/pci/Kconfig
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ac97/ac97_pcm.c
sound/pci/ac97/ac97_proc.c
sound/pci/ac97/ak4531_codec.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/au88x0/au88x0_mpu401.c
sound/pci/au88x0/au88x0_xtalk.c
sound/pci/azt3328.c
sound/pci/azt3328.h
sound/pci/bt87x.c
sound/pci/ca0106/ca0106.h
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/ca0106/ca0106_proc.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs5535audio/Makefile
sound/pci/cs5535audio/cs5535audio.c
sound/pci/cs5535audio/cs5535audio.h
sound/pci/cs5535audio/cs5535audio_pcm.c
sound/pci/cs5535audio/cs5535audio_pm.c [new file with mode: 0644]
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emuproc.c
sound/pci/emu10k1/io.c
sound/pci/emu10k1/memory.c
sound/pci/emu10k1/p17v.h [new file with mode: 0644]
sound/pci/emu10k1/tina2.h
sound/pci/emu10k1/voice.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_patch.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_atihdmi.c [new file with mode: 0644]
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/aureon.h
sound/pci/ice1712/ews.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/pontis.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/pcxhr/pcxhr.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/trident/trident_main.c
sound/pci/trident/trident_memory.c
sound/pci/trident/trident_synth.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/pdaudiocf/pdaudiocf_core.c
sound/pcmcia/vx/vxp_ops.c
sound/pcmcia/vx/vxpocket.c
sound/ppc/Makefile
sound/ppc/pmac.c
sound/ppc/pmac.h
sound/ppc/powermac.c
sound/ppc/toonie.c
sound/sparc/dbri.c
sound/synth/emux/emux.c
sound/synth/emux/emux_proc.c
sound/synth/emux/emux_seq.c
sound/synth/emux/emux_synth.c
sound/synth/emux/soundfont.c
sound/usb/usbaudio.c
sound/usb/usbaudio.h
sound/usb/usbmidi.c
sound/usb/usbmixer.c
sound/usb/usx2y/usx2yhwdeppcm.c

diff --git a/Documentation/ABI/README b/Documentation/ABI/README
new file mode 100644 (file)
index 0000000..9feaf16
--- /dev/null
@@ -0,0 +1,77 @@
+This directory attempts to document the ABI between the Linux kernel and
+userspace, and the relative stability of these interfaces.  Due to the
+everchanging nature of Linux, and the differing maturity levels, these
+interfaces should be used by userspace programs in different ways.
+
+We have four different levels of ABI stability, as shown by the four
+different subdirectories in this location.  Interfaces may change levels
+of stability according to the rules described below.
+
+The different levels of stability are:
+
+  stable/
+       This directory documents the interfaces that the developer has
+       defined to be stable.  Userspace programs are free to use these
+       interfaces with no restrictions, and backward compatibility for
+       them will be guaranteed for at least 2 years.  Most interfaces
+       (like syscalls) are expected to never change and always be
+       available.
+
+  testing/
+       This directory documents interfaces that are felt to be stable,
+       as the main development of this interface has been completed.
+       The interface can be changed to add new features, but the
+       current interface will not break by doing this, unless grave
+       errors or security problems are found in them.  Userspace
+       programs can start to rely on these interfaces, but they must be
+       aware of changes that can occur before these interfaces move to
+       be marked stable.  Programs that use these interfaces are
+       strongly encouraged to add their name to the description of
+       these interfaces, so that the kernel developers can easily
+       notify them if any changes occur (see the description of the
+       layout of the files below for details on how to do this.)
+
+  obsolete/
+       This directory documents interfaces that are still remaining in
+       the kernel, but are marked to be removed at some later point in
+       time.  The description of the interface will document the reason
+       why it is obsolete and when it can be expected to be removed.
+       The file Documentation/feature-removal-schedule.txt may describe
+       some of these interfaces, giving a schedule for when they will
+       be removed.
+
+  removed/
+       This directory contains a list of the old interfaces that have
+       been removed from the kernel.
+
+Every file in these directories will contain the following information:
+
+What:          Short description of the interface
+Date:          Date created
+KernelVersion: Kernel version this feature first showed up in.
+Contact:       Primary contact for this interface (may be a mailing list)
+Description:   Long description of the interface and how to use it.
+Users:         All users of this interface who wish to be notified when
+               it changes.  This is very important for interfaces in
+               the "testing" stage, so that kernel developers can work
+               with userspace developers to ensure that things do not
+               break in ways that are unacceptable.  It is also
+               important to get feedback for these interfaces to make
+               sure they are working in a proper way and do not need to
+               be changed further.
+
+
+How things move between levels:
+
+Interfaces in stable may move to obsolete, as long as the proper
+notification is given.
+
+Interfaces may be removed from obsolete and the kernel as long as the
+documented amount of time has gone by.
+
+Interfaces in the testing state can move to the stable state when the
+developers feel they are finished.  They cannot be removed from the
+kernel tree without going through the obsolete state first.
+
+It's up to the developer to place their interfaces in the category they
+wish for it to start out in.
diff --git a/Documentation/ABI/obsolete/devfs b/Documentation/ABI/obsolete/devfs
new file mode 100644 (file)
index 0000000..b8b8739
--- /dev/null
@@ -0,0 +1,13 @@
+What:          devfs
+Date:          July 2005
+Contact:       Greg Kroah-Hartman <gregkh@suse.de>
+Description:
+       devfs has been unmaintained for a number of years, has unfixable
+       races, contains a naming policy within the kernel that is
+       against the LSB, and can be replaced by using udev.
+       The files fs/devfs/*, include/linux/devfs_fs*.h will be removed,
+       along with the the assorted devfs function calls throughout the
+       kernel tree.
+
+Users:
+
diff --git a/Documentation/ABI/stable/syscalls b/Documentation/ABI/stable/syscalls
new file mode 100644 (file)
index 0000000..c3ae3e7
--- /dev/null
@@ -0,0 +1,10 @@
+What:          The kernel syscall interface
+Description:
+       This interface matches much of the POSIX interface and is based
+       on it and other Unix based interfaces.  It will only be added to
+       over time, and not have things removed from it.
+
+       Note that this interface is different for every architecture
+       that Linux supports.  Please see the architecture-specific
+       documentation for details on the syscall numbers that are to be
+       mapped to each syscall.
diff --git a/Documentation/ABI/stable/sysfs-module b/Documentation/ABI/stable/sysfs-module
new file mode 100644 (file)
index 0000000..75be431
--- /dev/null
@@ -0,0 +1,30 @@
+What:          /sys/module
+Description:
+       The /sys/module tree consists of the following structure:
+
+       /sys/module/MODULENAME
+               The name of the module that is in the kernel.  This
+               module name will show up either if the module is built
+               directly into the kernel, or if it is loaded as a
+               dyanmic module.
+
+       /sys/module/MODULENAME/parameters
+               This directory contains individual files that are each
+               individual parameters of the module that are able to be
+               changed at runtime.  See the individual module
+               documentation as to the contents of these parameters and
+               what they accomplish.
+
+               Note: The individual parameter names and values are not
+               considered stable, only the fact that they will be
+               placed in this location within sysfs.  See the
+               individual driver documentation for details as to the
+               stability of the different parameters.
+
+       /sys/module/MODULENAME/refcnt
+               If the module is able to be unloaded from the kernel, this file
+               will contain the current reference count of the module.
+
+               Note: If the module is built into the kernel, or if the
+               CONFIG_MODULE_UNLOAD kernel configuration value is not enabled,
+               this file will not be present.
diff --git a/Documentation/ABI/testing/sysfs-class b/Documentation/ABI/testing/sysfs-class
new file mode 100644 (file)
index 0000000..4b0cb89
--- /dev/null
@@ -0,0 +1,16 @@
+What:          /sys/class/
+Date:          Febuary 2006
+Contact:       Greg Kroah-Hartman <gregkh@suse.de>
+Description:
+               The /sys/class directory will consist of a group of
+               subdirectories describing individual classes of devices
+               in the kernel.  The individual directories will consist
+               of either subdirectories, or symlinks to other
+               directories.
+
+               All programs that use this directory tree must be able
+               to handle both subdirectories or symlinks in order to
+               work properly.
+
+Users:
+       udev <linux-hotplug-devel@lists.sourceforge.net>
diff --git a/Documentation/ABI/testing/sysfs-devices b/Documentation/ABI/testing/sysfs-devices
new file mode 100644 (file)
index 0000000..6a25671
--- /dev/null
@@ -0,0 +1,25 @@
+What:          /sys/devices
+Date:          February 2006
+Contact:       Greg Kroah-Hartman <gregkh@suse.de>
+Description:
+               The /sys/devices tree contains a snapshot of the
+               internal state of the kernel device tree.  Devices will
+               be added and removed dynamically as the machine runs,
+               and between different kernel versions, the layout of the
+               devices within this tree will change.
+
+               Please do not rely on the format of this tree because of
+               this.  If a program wishes to find different things in
+               the tree, please use the /sys/class structure and rely
+               on the symlinks there to point to the proper location
+               within the /sys/devices tree of the individual devices.
+               Or rely on the uevent messages to notify programs of
+               devices being added and removed from this tree to find
+               the location of those devices.
+
+               Note that sometimes not all devices along the directory
+               chain will have emitted uevent messages, so userspace
+               programs must be able to handle such occurrences.
+
+Users:
+       udev <linux-hotplug-devel@lists.sourceforge.net>
index 85a64defd3856eb24e97540d07f40dfae2c6b5f0..fa0d4cca964acc1ff3cc73a342ef9c3592ca3322 100644 (file)
@@ -124,7 +124,8 @@ GigaSet 307x Device Driver
 
      You can use some configuration tool of your distribution to configure this
      "modem" or configure pppd/wvdial manually. There are some example ppp
-     configuration files and chat scripts in the gigaset-VERSION/ppp directory.
+     configuration files and chat scripts in the gigaset-VERSION/ppp directory
+     in the driver packages from http://sourceforge.net/projects/gigaset307x/.
      Please note that the USB drivers are not able to change the state of the
      control lines (the M105 driver can be configured to use some undocumented
      control requests, if you really need the control lines, though). This means
@@ -164,8 +165,8 @@ GigaSet 307x Device Driver
 
      If you want both of these at once, you are out of luck.
 
-     You can also use /sys/module/<name>/parameters/cidmode for changing
-     the CID mode setting (<name> is usb_gigaset or bas_gigaset).
+     You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode
+     setting (ttyGxy is ttyGU0 or ttyGB0).
 
 
 3.   Troubleshooting
index aaa01b0e3ee94251476d15f2ae6574844af9bb16..3bbe157b45e470ca656c72e47e523138c9be6fe8 100644 (file)
@@ -19,6 +19,7 @@ This document has the following sections:
        - Key overview
        - Key service overview
        - Key access permissions
+       - SELinux support
        - New procfs files
        - Userspace system call interface
        - Kernel services
@@ -232,6 +233,34 @@ For changing the ownership, group ID or permissions mask, being the owner of
 the key or having the sysadmin capability is sufficient.
 
 
+===============
+SELINUX SUPPORT
+===============
+
+The security class "key" has been added to SELinux so that mandatory access
+controls can be applied to keys created within various contexts.  This support
+is preliminary, and is likely to change quite significantly in the near future.
+Currently, all of the basic permissions explained above are provided in SELinux
+as well; SE Linux is simply invoked after all basic permission checks have been
+performed.
+
+Each key is labeled with the same context as the task to which it belongs.
+Typically, this is the same task that was running when the key was created.
+The default keyrings are handled differently, but in a way that is very
+intuitive:
+
+ (*) The user and user session keyrings that are created when the user logs in
+     are currently labeled with the context of the login manager.
+
+ (*) The keyrings associated with new threads are each labeled with the context
+     of their associated thread, and both session and process keyrings are
+     handled similarly.
+
+Note, however, that the default keyrings associated with the root user are
+labeled with the default kernel context, since they are created early in the
+boot process, before root has a chance to log in.
+
+
 ================
 NEW PROCFS FILES
 ================
@@ -935,6 +964,16 @@ The structure has a number of fields, some of which are mandatory:
      It is not safe to sleep in this method; the caller may hold spinlocks.
 
 
+ (*) void (*revoke)(struct key *key);
+
+     This method is optional.  It is called to discard part of the payload
+     data upon a key being revoked.  The caller will have the key semaphore
+     write-locked.
+
+     It is safe to sleep in this method, though care should be taken to avoid
+     a deadlock against the key semaphore.
+
+
  (*) void (*destroy)(struct key *key);
 
      This method is optional. It is called to discard the payload data on a key
index f987afe43e28e1327ee76ab4f3fdb617abfe0829..fba1e05c47c72e558e162c2153d5feee62a4c97f 100644 (file)
@@ -118,96 +118,6 @@ will fail.
 There is currently no way to know what states a device or driver
 supports a priori. This will change in the future. 
 
-pm_message_t meaning
-
-pm_message_t has two fields. event ("major"), and flags.  If driver
-does not know event code, it aborts the request, returning error. Some
-drivers may need to deal with special cases based on the actual type
-of suspend operation being done at the system level. This is why
-there are flags.
-
-Event codes are:
-
-ON -- no need to do anything except special cases like broken
-HW.
-
-# NOTIFICATION -- pretty much same as ON?
-
-FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from
-scratch. That probably means stop accepting upstream requests, the
-actual policy of what to do with them beeing specific to a given
-driver. It's acceptable for a network driver to just drop packets
-while a block driver is expected to block the queue so no request is
-lost. (Use IDE as an example on how to do that). FREEZE requires no
-power state change, and it's expected for drivers to be able to
-quickly transition back to operating state.
-
-SUSPEND -- like FREEZE, but also put hardware into low-power state. If
-there's need to distinguish several levels of sleep, additional flag
-is probably best way to do that.
-
-Transitions are only from a resumed state to a suspended state, never
-between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen,
-FREEZE -> SUSPEND or SUSPEND -> FREEZE can not).
-
-All events are:
-
-[NOTE NOTE NOTE: If you are driver author, you should not care; you
-should only look at event, and ignore flags.]
-
-#Prepare for suspend -- userland is still running but we are going to
-#enter suspend state. This gives drivers chance to load firmware from
-#disk and store it in memory, or do other activities taht require
-#operating userland, ability to kmalloc GFP_KERNEL, etc... All of these
-#are forbiden once the suspend dance is started.. event = ON, flags =
-#PREPARE_TO_SUSPEND
-
-Apm standby -- prepare for APM event. Quiesce devices to make life
-easier for APM BIOS. event = FREEZE, flags = APM_STANDBY
-
-Apm suspend -- same as APM_STANDBY, but it we should probably avoid
-spinning down disks. event = FREEZE, flags = APM_SUSPEND
-
-System halt, reboot -- quiesce devices to make life easier for BIOS. event
-= FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT
-
-System shutdown -- at least disks need to be spun down, or data may be
-lost. Quiesce devices, just to make life easier for BIOS. event =
-FREEZE, flags = SYSTEM_SHUTDOWN
-
-Kexec    -- turn off DMAs and put hardware into some state where new
-kernel can take over. event = FREEZE, flags = KEXEC
-
-Powerdown at end of swsusp -- very similar to SYSTEM_SHUTDOWN, except wake
-may need to be enabled on some devices. This actually has at least 3
-subtypes, system can reboot, enter S4 and enter S5 at the end of
-swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT,
-SYSTEM_SHUTDOWN, SYSTEM_S4
-
-Suspend to ram  -- put devices into low power state. event = SUSPEND,
-flags = SUSPEND_TO_RAM
-
-Freeze for swsusp snapshot -- stop DMA and interrupts. No need to put
-devices into low power mode, but you must be able to reinitialize
-device from scratch in resume method. This has two flavors, its done
-once on suspending kernel, once on resuming kernel. event = FREEZE,
-flags = DURING_SUSPEND or DURING_RESUME
-
-Device detach requested from /sys -- deinitialize device; proably same as
-SYSTEM_SHUTDOWN, I do not understand this one too much. probably event
-= FREEZE, flags = DEV_DETACH.
-
-#These are not really events sent:
-#
-#System fully on -- device is working normally; this is probably never
-#passed to suspend() method... event = ON, flags = 0
-#
-#Ready after resume -- userland is now running, again. Time to free any
-#memory you ate during prepare to suspend... event = ON, flags =
-#READY_AFTER_RESUME
-#
-
-
 pm_message_t meaning
 
 pm_message_t has two fields. event ("major"), and flags.  If driver
index d7814a113ee1752a7c91c54ae6841407baa73370..516c5019013b0906bf2d0e513816b6821bae9713 100644 (file)
@@ -18,10 +18,11 @@ Some warnings, first.
  *
  * (*) suspend/resume support is needed to make it safe.
  *
- * If you have any filesystems on USB devices mounted before suspend,
+ * If you have any filesystems on USB devices mounted before software suspend,
  * they won't be accessible after resume and you may lose data, as though
- * you have unplugged the USB devices with mounted filesystems on them
- * (see the FAQ below for details).
+ * you have unplugged the USB devices with mounted filesystems on them;
+ * see the FAQ below for details.  (This is not true for more traditional
+ * power states like "standby", which normally don't turn USB off.)
 
 You need to append resume=/dev/your_swap_partition to kernel command
 line. Then you suspend by
@@ -204,7 +205,7 @@ Q: There don't seem to be any generally useful behavioral
 distinctions between SUSPEND and FREEZE.
 
 A: Doing SUSPEND when you are asked to do FREEZE is always correct,
-but it may be unneccessarily slow. If you want USB to stay simple,
+but it may be unneccessarily slow. If you want your driver to stay simple,
 slowness may not matter to you. It can always be fixed later.
 
 For devices like disk it does matter, you do not want to spindown for
@@ -357,17 +358,25 @@ Q: Is this true that if I have a mounted filesystem on a USB device and
 I suspend to disk, I can lose data unless the filesystem has been mounted
 with "sync"?
 
-A: That's right.  It depends on your hardware, and it could be true even for
-suspend-to-RAM.  In fact, even with "-o sync" you can lose data if your
-programs have information in buffers they haven't written out to disk.
+A: That's right ... if you disconnect that device, you may lose data.
+In fact, even with "-o sync" you can lose data if your programs have
+information in buffers they haven't written out to a disk you disconnect,
+or if you disconnect before the device finished saving data you wrote.
 
-If you're lucky, your hardware will support low-power modes for USB
-controllers while the system is asleep.  Lots of hardware doesn't,
-however.  Shutting off the power to a USB controller is equivalent to
-unplugging all the attached devices.
+Software suspend normally powers down USB controllers, which is equivalent
+to disconnecting all USB devices attached to your system.
+
+Your system might well support low-power modes for its USB controllers
+while the system is asleep, maintaining the connection, using true sleep
+modes like "suspend-to-RAM" or "standby".  (Don't write "disk" to the
+/sys/power/state file; write "standby" or "mem".)  We've not seen any
+hardware that can use these modes through software suspend, although in
+theory some systems might support "platform" or "firmware" modes that
+won't break the USB connections.
 
 Remember that it's always a bad idea to unplug a disk drive containing a
-mounted filesystem.  With USB that's true even when your system is asleep!
-The safest thing is to unmount all USB-based filesystems before suspending
-and remount them after resuming.
+mounted filesystem.  That's true even when your system is asleep!  The
+safest thing is to unmount all filesystems on removable media (such USB,
+Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays)
+before suspending; then remount them after resuming.
 
index 0ee2c7dfc4829cd0a4bd1374dd27aeb213a79a16..87d76a5c73d05742c0532d702819111681730af9 100644 (file)
@@ -366,7 +366,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for C-Media CMI8338 and 8738 PCI sound cards.
 
-    mpu_port   - 0x300,0x310,0x320,0x330, 0 = disable (default)
+    mpu_port   - 0x300,0x310,0x320,0x330 = legacy port,
+                 1 = integrated PCI port,
+                 0 = disable (default)
     fm_port     - 0x388 (default), 0 = disable (default)
     soft_ac3    - Software-conversion of raw SPDIF packets (model 033 only)
                   (default = 1)
@@ -468,7 +470,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for multifunction CS5535 companion PCI device
 
-    This module supports multiple cards.
+    The power-management is supported.
 
   Module snd-dt019x
   -----------------
@@ -707,8 +709,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-hda-intel
   --------------------
 
-    Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450,
-              VIA VT8251/VT8237A
+    Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8),
+               ATI SB450, SB600, RS600,
+               VIA VT8251/VT8237A,
+               SIS966, ULI M5461
 
     model      - force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
@@ -778,6 +782,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
        AD1981
          basic         3-jack (default)
          hp            HP nx6320
+         thinkpad      Lenovo Thinkpad T60/X60/Z60
 
        AD1986A
          6stack        6-jack, separate surrounds (default)
@@ -1633,9 +1638,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     About capture IBL, see the description of snd-vx222 module.
 
-    Note: the driver is build only when CONFIG_ISA is set.
-    
-    Note2: snd-vxp440 driver is merged to snd-vxpocket driver since
+    Note: snd-vxp440 driver is merged to snd-vxpocket driver since
            ALSA 1.0.10.
 
     The power-management is supported.
@@ -1662,8 +1665,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for Sound Core PDAudioCF sound card.
 
-    Note: the driver is build only when CONFIG_ISA is set.
-
     The power-management is supported.
 
 
index 1faf76383babd26875c9e5d303685a29c6096531..635cbb94357cd575bc46ae3328179dc4cac5ced1 100644 (file)
@@ -4215,7 +4215,7 @@ struct _snd_pcm_runtime {
           <programlisting>
 <![CDATA[
   struct snd_rawmidi *rmidi;
-  snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, integrated,
+  snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, info_flags,
                       irq, irq_flags, &rmidi);
 ]]>
           </programlisting>
@@ -4242,15 +4242,36 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
+       The 5th argument is bitflags for additional information.
         When the i/o port address above is a part of the PCI i/o
       region, the MPU401 i/o port might have been already allocated
-      (reserved) by the driver itself. In such a case, pass non-zero
-      to the 5th argument
-      (<parameter>integrated</parameter>). Otherwise, pass 0 to it,
+      (reserved) by the driver itself. In such a case, pass a bit flag
+      <constant>MPU401_INFO_INTEGRATED</constant>,
       and 
       the mpu401-uart layer will allocate the i/o ports by itself. 
       </para>
 
+       <para>
+       When the controller supports only the input or output MIDI stream,
+       pass <constant>MPU401_INFO_INPUT</constant> or
+       <constant>MPU401_INFO_OUTPUT</constant> bitflag, respectively.
+       Then the rawmidi instance is created as a single stream.
+       </para>
+
+       <para>
+       <constant>MPU401_INFO_MMIO</constant> bitflag is used to change
+       the access method to MMIO (via readb and writeb) instead of
+       iob and outb.  In this case, you have to pass the iomapped address
+       to <function>snd_mpu401_uart_new()</function>.
+       </para>
+
+       <para>
+       When <constant>MPU401_INFO_TX_IRQ</constant> is set, the output
+       stream isn't checked in the default interrupt handler.  The driver
+       needs to call <function>snd_mpu401_uart_interrupt_tx()</function>
+       by itself to start processing the output stream in irq handler.
+       </para>
+
       <para>
         Usually, the port address corresponds to the command port and
         port + 1 corresponds to the data port. If not, you may change
@@ -5333,7 +5354,7 @@ struct _snd_pcm_runtime {
       <informalexample>
         <programlisting>
 <![CDATA[
-  snd_info_set_text_ops(entry, chip, read_size, my_proc_read);
+  snd_info_set_text_ops(entry, chip, my_proc_read);
 ]]>
         </programlisting>
       </informalexample>
@@ -5394,29 +5415,12 @@ struct _snd_pcm_runtime {
       <informalexample>
         <programlisting>
 <![CDATA[
-  entry->c.text.write_size = 256;
   entry->c.text.write = my_proc_write;
 ]]>
         </programlisting>
       </informalexample>
     </para>
 
-    <para>
-    The buffer size for read is set to 1024 implicitly by
-    <function>snd_info_set_text_ops()</function>.  It should suffice
-    in most cases (the size will be aligned to
-    <constant>PAGE_SIZE</constant> anyway), but if you need to handle
-    very large text files, you can set it explicitly, too.
-
-      <informalexample>
-        <programlisting>
-<![CDATA[
-  entry->c.text.read_size = 65536;
-]]>
-        </programlisting>
-      </informalexample>
-    </para>
-
     <para>
       For the write callback, you can use
     <function>snd_info_get_line()</function> to get a text line, and
@@ -5562,7 +5566,7 @@ struct _snd_pcm_runtime {
          power status.</para></listitem>
         <listitem><para>Call <function>snd_pcm_suspend_all()</function> to suspend the running PCM streams.</para></listitem>
        <listitem><para>If AC97 codecs are used, call
-       <function>snd_ac97_resume()</function> for each codec.</para></listitem>
+       <function>snd_ac97_suspend()</function> for each codec.</para></listitem>
         <listitem><para>Save the register values if necessary.</para></listitem>
         <listitem><para>Stop the hardware if necessary.</para></listitem>
         <listitem><para>Disable the PCI device by calling
index 63cb7edd177ef87e304fb7500596ffaa72c42633..e65ec828d7aa226f1fb8365c48afadb225dae79e 100644 (file)
@@ -29,14 +29,13 @@ if usbmon is built into the kernel.
 
 # mount -t debugfs none_debugs /sys/kernel/debug
 # modprobe usbmon
+#
 
 Verify that bus sockets are present.
 
-[root@lembas zaitcev]# ls /sys/kernel/debug/usbmon
+# ls /sys/kernel/debug/usbmon
 1s  1t  2s  2t  3s  3t  4s  4t
-[root@lembas zaitcev]#
-
-# ls /sys/kernel
+#
 
 2. Find which bus connects to the desired device
 
@@ -76,7 +75,7 @@ that the file size is not excessive for your favourite editor.
 
 * Raw text data format
 
-The '0t' type data consists of a stream of events, such as URB submission,
+The '1t' type data consists of a stream of events, such as URB submission,
 URB callback, submission error. Every event is a text line, which consists
 of whitespace separated words. The number of position of words may depend
 on the event type, but there is a set of words, common for all types.
@@ -97,20 +96,25 @@ Here is the list of words, from left to right:
     Zi Zo   Isochronous input and output
     Ii Io   Interrupt input and output
     Bi Bo   Bulk input and output
-  Device address and Endpoint number are decimal numbers with leading zeroes
-  or 3 and 2 positions, correspondingly.
-- URB Status. This field makes no sense for submissions, but is present
-  to help scripts with parsing. In error case, it contains the error code.
-  In case of a setup packet, it contains a Setup Tag. If scripts read a number
-  in this field, they proceed to read Data Length. Otherwise, they read
-  the setup packet before reading the Data Length.
+  Device address and Endpoint number are 3-digit and 2-digit (respectively)
+  decimal numbers, with leading zeroes.
+- URB Status. In most cases, this field contains a number, sometimes negative,
+  which represents a "status" field of the URB. This field makes no sense for
+  submissions, but is present anyway to help scripts with parsing. When an
+  error occurs, the field contains the error code. In case of a submission of
+  a Control packet, this field contains a Setup Tag instead of an error code.
+  It is easy to tell whether the Setup Tag is present because it is never a
+  number. Thus if scripts find a number in this field, they proceed to read
+  Data Length. If they find something else, like a letter, they read the setup
+  packet before reading the Data Length.
 - Setup packet, if present, consists of 5 words: one of each for bmRequestType,
   bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
   These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
   packet was present, but not captured, and the fields contain filler.
-- Data Length. This is the actual length in the URB.
+- Data Length. For submissions, this is the requested length. For callbacks,
+  this is the actual length.
 - Data tag. The usbmon may not always capture data, even if length is nonzero.
-  Only if tag is '=', the data words are present.
+  The data words are present only if this tag is '='.
 - Data words follow, in big endian hexadecimal format. Notice that they are
   not machine words, but really just a byte stream split into words to make
   it easier to read. Thus, the last word may contain from one to four bytes.
index 0692c33d13cd340bafa6f224fa2aa18358ae010f..d10e629db5630de18fe9df492fa0df644a8ec78b 100644 (file)
@@ -3191,7 +3191,7 @@ XFS FILESYSTEM
 P:     Silicon Graphics Inc
 M:     xfs-masters@oss.sgi.com
 M:     nathans@sgi.com
-L:     linux-xfs@oss.sgi.com
+L:     xfs@oss.sgi.com
 W:     http://oss.sgi.com/projects/xfs
 S:     Supported
 
index 840ae595a6178e29c6f0089af02d3213a03369b9..d961bfeed05fccbdfbf4a1094fc7ec7a240fce8c 100644 (file)
@@ -29,8 +29,8 @@ OBJCOPYFLAGS    := contents,alloc,load,readonly,data
 OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
 OBJCOPY_MIB_ARGS  := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
 
-zlib       := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
-zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
+zlib       := inffast.c inflate.c inftrees.c
+zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
 zliblinuxheader := zlib.h zconf.h zutil.h
 
 $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
index ceb584682fa30f64d9c7bbc3d84af53db5d2d8f0..71a3275935eca1cc76ec0d3f75ccddb62b5461a1 100644 (file)
@@ -372,7 +372,7 @@ static int __init fsl_usb_of_init(void)
 {
        struct device_node *np;
        unsigned int i;
-       struct platform_device *usb_dev;
+       struct platform_device *usb_dev_mph = NULL, *usb_dev_dr = NULL;
        int ret;
 
        for (np = NULL, i = 0;
@@ -393,15 +393,15 @@ static int __init fsl_usb_of_init(void)
                r[1].end = np->intrs[0].line;
                r[1].flags = IORESOURCE_IRQ;
 
-               usb_dev =
-                   platform_device_register_simple("fsl-usb2-mph", i, r, 2);
-               if (IS_ERR(usb_dev)) {
-                       ret = PTR_ERR(usb_dev);
+               usb_dev_mph =
+                   platform_device_register_simple("fsl-ehci", i, r, 2);
+               if (IS_ERR(usb_dev_mph)) {
+                       ret = PTR_ERR(usb_dev_mph);
                        goto err;
                }
 
-               usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
-               usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
+               usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
+               usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
 
                usb_data.operating_mode = FSL_USB2_MPH_HOST;
 
@@ -417,31 +417,14 @@ static int __init fsl_usb_of_init(void)
                usb_data.phy_mode = determine_usb_phy(prop);
 
                ret =
-                   platform_device_add_data(usb_dev, &usb_data,
+                   platform_device_add_data(usb_dev_mph, &usb_data,
                                             sizeof(struct
                                                    fsl_usb2_platform_data));
                if (ret)
-                       goto unreg;
+                       goto unreg_mph;
        }
 
-       return 0;
-
-unreg:
-       platform_device_unregister(usb_dev);
-err:
-       return ret;
-}
-
-arch_initcall(fsl_usb_of_init);
-
-static int __init fsl_usb_dr_of_init(void)
-{
-       struct device_node *np;
-       unsigned int i;
-       struct platform_device *usb_dev;
-       int ret;
-
-       for (np = NULL, i = 0;
+       for (np = NULL;
             (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL;
             i++) {
                struct resource r[2];
@@ -453,21 +436,21 @@ static int __init fsl_usb_dr_of_init(void)
 
                ret = of_address_to_resource(np, 0, &r[0]);
                if (ret)
-                       goto err;
+                       goto unreg_mph;
 
                r[1].start = np->intrs[0].line;
                r[1].end = np->intrs[0].line;
                r[1].flags = IORESOURCE_IRQ;
 
-               usb_dev =
-                   platform_device_register_simple("fsl-usb2-dr", i, r, 2);
-               if (IS_ERR(usb_dev)) {
-                       ret = PTR_ERR(usb_dev);
+               usb_dev_dr =
+                   platform_device_register_simple("fsl-ehci", i, r, 2);
+               if (IS_ERR(usb_dev_dr)) {
+                       ret = PTR_ERR(usb_dev_dr);
                        goto err;
                }
 
-               usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
-               usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
+               usb_dev_dr->dev.coherent_dma_mask = 0xffffffffUL;
+               usb_dev_dr->dev.dma_mask = &usb_dev_dr->dev.coherent_dma_mask;
 
                usb_data.operating_mode = FSL_USB2_DR_HOST;
 
@@ -475,19 +458,22 @@ static int __init fsl_usb_dr_of_init(void)
                usb_data.phy_mode = determine_usb_phy(prop);
 
                ret =
-                   platform_device_add_data(usb_dev, &usb_data,
+                   platform_device_add_data(usb_dev_dr, &usb_data,
                                             sizeof(struct
                                                    fsl_usb2_platform_data));
                if (ret)
-                       goto unreg;
+                       goto unreg_dr;
        }
-
        return 0;
 
-unreg:
-       platform_device_unregister(usb_dev);
+unreg_dr:
+       if (usb_dev_dr)
+               platform_device_unregister(usb_dev_dr);
+unreg_mph:
+       if (usb_dev_mph)
+               platform_device_unregister(usb_dev_mph);
 err:
        return ret;
 }
 
-arch_initcall(fsl_usb_dr_of_init);
+arch_initcall(fsl_usb_of_init);
index 80c84d562fa4ac173b595cd22cdd4d2e02540f2c..2f995f712ec55c90857bd71539f5f34b90df64f7 100644 (file)
@@ -5,7 +5,7 @@
 CFLAGS_kbd.o   := -Idrivers/char
 CFLAGS_vreset.o := -Iarch/ppc/boot/include
 
-zlib  := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+zlib  := inffast.c inflate.c inftrees.c
         
 lib-y += $(zlib:.c=.o) div64.o
 lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o
index 1af2c000fcfa6ebdf47fdc9b9e3072fd9fdc948e..5c4932ca8e9b8a5f6ae0ce5fdb495a441679575e 100644 (file)
@@ -186,7 +186,7 @@ struct platform_device ppc_sys_platform_devices[] = {
                },
        },
        [MPC83xx_USB2_DR] = {
-               .name = "fsl-usb2-dr",
+               .name = "fsl-ehci",
                .id     = 1,
                .num_resources   = 2,
                .resource = (struct resource[]) {
@@ -203,8 +203,8 @@ struct platform_device ppc_sys_platform_devices[] = {
                },
        },
        [MPC83xx_USB2_MPH] = {
-               .name = "fsl-usb2-mph",
-               .id     = 1,
+               .name = "fsl-ehci",
+               .id     = 2,
                .num_resources   = 2,
                .resource = (struct resource[]) {
                        {
index 2cbf282f0d004d9bdf2813b043fffa0f0e1f096d..a893a9cc953473a335668569407c0b8d7a35ccf1 100644 (file)
@@ -332,7 +332,7 @@ void __init setup_arch(char **cmdline_p)
        if (!root_flags)
                root_mountflags &= ~MS_RDONLY;
        ROOT_DEV = old_decode_dev(root_dev);
-#ifdef CONFIG_BLK_DEV_INITRD
+#ifdef CONFIG_BLK_DEV_RAM
        rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
        rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
        rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
index 86f51d04c98df366d7a139468cf3afb08c402251..87cdbc560d360a3c62c4c144645e096225765d67 100644 (file)
@@ -87,7 +87,7 @@ void timer_irq(union uml_pt_regs *regs)
 
 void time_init_kern(void)
 {
-       unsigned long long nsecs;
+       long long nsecs;
 
        nsecs = os_nsecs();
        set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION,
index 408d44a59756f8050c4455fdbb471eb9c9881f09..7d3bc5ac5db0ab7a8fbb156e5a4a8d6c80186979 100644 (file)
@@ -389,6 +389,7 @@ config GART_IOMMU
        bool "K8 GART IOMMU support"
        default y
        select SWIOTLB
+       select AGP
        depends on PCI
        help
          Support for hardware IOMMU in AMD's Opteron/Athlon64 Processors
@@ -401,11 +402,9 @@ config GART_IOMMU
          northbridge and a software emulation used on other systems without
          hardware IOMMU.  If unsure, say Y.
 
-# need this always enabled with GART_IOMMU for the VIA workaround
+# need this always selected by GART_IOMMU for the VIA workaround
 config SWIOTLB
        bool
-       default y
-       depends on GART_IOMMU
 
 config X86_MCE
        bool "Machine check support" if EMBEDDED
index 9e73bb8aeb7affb3216c8eb16b8f617f15874781..d3d2aa2d883aa6e4d9abfc7571b7e3e5eadbc30f 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for some libs needed by zImage.
 #
 
-zlib   := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+zlib   := inffast.c inflate.c inftrees.c
 
 lib-y  += $(zlib:.c=.o) zmem.o
 
index 5a8d3bf02f1715702fe94515339f1cdfbfd3d088..8d7339511e5e962dfccca43298a06e24a48df846 100644 (file)
@@ -17,8 +17,7 @@
 #include <linux/buffer_head.h>
 #include <linux/mutex.h>
 
-static struct subsystem block_subsys;
-
+struct subsystem block_subsys;
 static DEFINE_MUTEX(block_subsys_lock);
 
 /*
@@ -511,9 +510,7 @@ static struct kset_uevent_ops block_uevent_ops = {
        .uevent         = block_uevent,
 };
 
-/* declare block_subsys. */
-static decl_subsys(block, &ktype_block, &block_uevent_ops);
-
+decl_subsys(block, &ktype_block, &block_uevent_ops);
 
 /*
  * aggregate disk stat collector.  Uses the same stats that the sysfs
index f0eff3dac58d4db1b7d3d1da6e927cb2135ba795..80502dc6ed668dbee5bc388520e1a819d8449959 100644 (file)
@@ -38,3 +38,7 @@ config DEBUG_DRIVER
          If you are unsure about this, say N here.
 
 endmenu
+
+config SYS_HYPERVISOR
+       bool
+       default n
index e99471d3232bb6d3fc70a33263986e2908d8751d..b539e5e75b5690116f868c9ea06283c758f6f7a7 100644 (file)
@@ -5,10 +5,12 @@ obj-y                 := core.o sys.o bus.o dd.o \
                           cpu.o firmware.o init.o map.o dmapool.o \
                           attribute_container.o transport_class.o
 obj-y                  += power/
+obj-$(CONFIG_ISA)      += isa.o
 obj-$(CONFIG_FW_LOADER)        += firmware_class.o
 obj-$(CONFIG_NUMA)     += node.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o
 obj-$(CONFIG_SMP)      += topology.o
+obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
 EXTRA_CFLAGS += -DDEBUG
index 2a7d7ae83e1eaf5ab65c9fd38ae7be47dce83763..22220733f76f5dbf417b1f1df670e561a6fb9192 100644 (file)
@@ -236,7 +236,6 @@ attribute_container_remove_device(struct device *dev,
        }
        up(&attribute_container_mutex);
 }
-EXPORT_SYMBOL_GPL(attribute_container_remove_device);
 
 /**
  * attribute_container_device_trigger - execute a trigger for each matching classdev
@@ -276,7 +275,6 @@ attribute_container_device_trigger(struct device *dev,
        }
        up(&attribute_container_mutex);
 }
-EXPORT_SYMBOL_GPL(attribute_container_device_trigger);
 
 /**
  * attribute_container_trigger - trigger a function for each matching container
@@ -304,7 +302,6 @@ attribute_container_trigger(struct device *dev,
        }
        up(&attribute_container_mutex);
 }
-EXPORT_SYMBOL_GPL(attribute_container_trigger);
 
 /**
  * attribute_container_add_attrs - add attributes
@@ -333,7 +330,6 @@ attribute_container_add_attrs(struct class_device *classdev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(attribute_container_add_attrs);
 
 /**
  * attribute_container_add_class_device - same function as class_device_add
@@ -352,7 +348,6 @@ attribute_container_add_class_device(struct class_device *classdev)
                return error;
        return attribute_container_add_attrs(classdev);
 }
-EXPORT_SYMBOL_GPL(attribute_container_add_class_device);
 
 /**
  * attribute_container_add_class_device_adapter - simple adapter for triggers
@@ -367,7 +362,6 @@ attribute_container_add_class_device_adapter(struct attribute_container *cont,
 {
        return attribute_container_add_class_device(classdev);
 }
-EXPORT_SYMBOL_GPL(attribute_container_add_class_device_adapter);
 
 /**
  * attribute_container_remove_attrs - remove any attribute files
@@ -389,7 +383,6 @@ attribute_container_remove_attrs(struct class_device *classdev)
        for (i = 0; attrs[i]; i++)
                class_device_remove_file(classdev, attrs[i]);
 }
-EXPORT_SYMBOL_GPL(attribute_container_remove_attrs);
 
 /**
  * attribute_container_class_device_del - equivalent of class_device_del
@@ -405,7 +398,6 @@ attribute_container_class_device_del(struct class_device *classdev)
        attribute_container_remove_attrs(classdev);
        class_device_del(classdev);
 }
-EXPORT_SYMBOL_GPL(attribute_container_class_device_del);
 
 /**
  * attribute_container_find_class_device - find the corresponding class_device
index 5735b38582d0381872e9fda2198f2bc10147b913..c3b8dc98b8a739812f78b5311b38bf18d671a8c7 100644 (file)
@@ -5,13 +5,21 @@ extern int devices_init(void);
 extern int buses_init(void);
 extern int classes_init(void);
 extern int firmware_init(void);
+#ifdef CONFIG_SYS_HYPERVISOR
+extern int hypervisor_init(void);
+#else
+static inline int hypervisor_init(void) { return 0; }
+#endif
 extern int platform_bus_init(void);
 extern int system_bus_init(void);
 extern int cpu_dev_init(void);
 extern int attribute_container_init(void);
 
 extern int bus_add_device(struct device * dev);
+extern void bus_attach_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
+extern struct bus_type *get_bus(struct bus_type * bus);
+extern void put_bus(struct bus_type * bus);
 
 extern int bus_add_driver(struct device_driver *);
 extern void bus_remove_driver(struct device_driver *);
@@ -34,4 +42,5 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
        return container_of(_attr, struct class_device_attribute, attr);
 }
 
+extern char *make_class_name(const char *name, struct kobject *kobj);
 
index 76656acd00d4e15c965c07a8a6ebcf1b4b511a42..050d86d0b872880c11807e9ece9bfd8f6b793377 100644 (file)
@@ -362,8 +362,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev)
  *     @dev:   device being added
  *
  *     - Add the device to its bus's list of devices.
- *     - Try to attach to driver.
- *     - Create link to device's physical location.
+ *     - Create link to device's bus.
  */
 int bus_add_device(struct device * dev)
 {
@@ -372,17 +371,32 @@ int bus_add_device(struct device * dev)
 
        if (bus) {
                pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
-               device_attach(dev);
-               klist_add_tail(&dev->knode_bus, &bus->klist_devices);
                error = device_add_attrs(bus, dev);
                if (!error) {
                        sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
+                       sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem");
                        sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
                }
        }
        return error;
 }
 
+/**
+ *     bus_attach_device - add device to bus
+ *     @dev:   device tried to attach to a driver
+ *
+ *     - Try to attach to driver.
+ */
+void bus_attach_device(struct device * dev)
+{
+       struct bus_type * bus = dev->bus;
+
+       if (bus) {
+               device_attach(dev);
+               klist_add_tail(&dev->knode_bus, &bus->klist_devices);
+       }
+}
+
 /**
  *     bus_remove_device - remove device from bus
  *     @dev:   device to be removed
@@ -395,6 +409,7 @@ int bus_add_device(struct device * dev)
 void bus_remove_device(struct device * dev)
 {
        if (dev->bus) {
+               sysfs_remove_link(&dev->kobj, "subsystem");
                sysfs_remove_link(&dev->kobj, "bus");
                sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
                device_remove_attrs(dev->bus, dev);
@@ -732,14 +747,9 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev);
 EXPORT_SYMBOL_GPL(bus_find_device);
 EXPORT_SYMBOL_GPL(bus_for_each_drv);
 
-EXPORT_SYMBOL_GPL(bus_add_device);
-EXPORT_SYMBOL_GPL(bus_remove_device);
 EXPORT_SYMBOL_GPL(bus_register);
 EXPORT_SYMBOL_GPL(bus_unregister);
 EXPORT_SYMBOL_GPL(bus_rescan_devices);
-EXPORT_SYMBOL_GPL(get_bus);
-EXPORT_SYMBOL_GPL(put_bus);
-EXPORT_SYMBOL_GPL(find_bus);
 
 EXPORT_SYMBOL_GPL(bus_create_file);
 EXPORT_SYMBOL_GPL(bus_remove_file);
index b1ea4df85c7dde7fc3289e27529bf1b85e785dda..9aa1274602625fa6beb6c463838d77a770800919 100644 (file)
@@ -91,14 +91,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
                sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr);
 }
 
-struct class * class_get(struct class * cls)
+static struct class *class_get(struct class *cls)
 {
        if (cls)
                return container_of(subsys_get(&cls->subsys), struct class, subsys);
        return NULL;
 }
 
-void class_put(struct class * cls)
+static void class_put(struct class * cls)
 {
        if (cls)
                subsys_put(&cls->subsys);
@@ -142,6 +142,7 @@ int class_register(struct class * cls)
        pr_debug("device class '%s': registering\n", cls->name);
 
        INIT_LIST_HEAD(&cls->children);
+       INIT_LIST_HEAD(&cls->devices);
        INIT_LIST_HEAD(&cls->interfaces);
        init_MUTEX(&cls->sem);
        error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
@@ -504,22 +505,21 @@ void class_device_initialize(struct class_device *class_dev)
        INIT_LIST_HEAD(&class_dev->node);
 }
 
-static char *make_class_name(struct class_device *class_dev)
+char *make_class_name(const char *name, struct kobject *kobj)
 {
-       char *name;
+       char *class_name;
        int size;
 
-       size = strlen(class_dev->class->name) +
-               strlen(kobject_name(&class_dev->kobj)) + 2;
+       size = strlen(name) + strlen(kobject_name(kobj)) + 2;
 
-       name = kmalloc(size, GFP_KERNEL);
-       if (!name)
+       class_name = kmalloc(size, GFP_KERNEL);
+       if (!class_name)
                return ERR_PTR(-ENOMEM);
 
-       strcpy(name, class_dev->class->name);
-       strcat(name, ":");
-       strcat(name, kobject_name(&class_dev->kobj));
-       return name;
+       strcpy(class_name, name);
+       strcat(class_name, ":");
+       strcat(class_name, kobject_name(kobj));
+       return class_name;
 }
 
 int class_device_add(struct class_device *class_dev)
@@ -535,18 +535,22 @@ int class_device_add(struct class_device *class_dev)
                return -EINVAL;
 
        if (!strlen(class_dev->class_id))
-               goto register_done;
+               goto out1;
 
        parent_class = class_get(class_dev->class);
        if (!parent_class)
-               goto register_done;
+               goto out1;
+
        parent_class_dev = class_device_get(class_dev->parent);
 
        pr_debug("CLASS: registering class device: ID = '%s'\n",
                 class_dev->class_id);
 
        /* first, register with generic layer. */
-       kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+       error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+       if (error)
+               goto out2;
+
        if (parent_class_dev)
                class_dev->kobj.parent = &parent_class_dev->kobj;
        else
@@ -554,41 +558,58 @@ int class_device_add(struct class_device *class_dev)
 
        error = kobject_add(&class_dev->kobj);
        if (error)
-               goto register_done;
+               goto out2;
 
        /* add the needed attributes to this device */
+       sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem");
        class_dev->uevent_attr.attr.name = "uevent";
        class_dev->uevent_attr.attr.mode = S_IWUSR;
        class_dev->uevent_attr.attr.owner = parent_class->owner;
        class_dev->uevent_attr.store = store_uevent;
-       class_device_create_file(class_dev, &class_dev->uevent_attr);
+       error = class_device_create_file(class_dev, &class_dev->uevent_attr);
+       if (error)
+               goto out3;
 
        if (MAJOR(class_dev->devt)) {
                struct class_device_attribute *attr;
                attr = kzalloc(sizeof(*attr), GFP_KERNEL);
                if (!attr) {
                        error = -ENOMEM;
-                       kobject_del(&class_dev->kobj);
-                       goto register_done;
+                       goto out4;
                }
                attr->attr.name = "dev";
                attr->attr.mode = S_IRUGO;
                attr->attr.owner = parent_class->owner;
                attr->show = show_dev;
-               class_device_create_file(class_dev, attr);
+               error = class_device_create_file(class_dev, attr);
+               if (error) {
+                       kfree(attr);
+                       goto out4;
+               }
+
                class_dev->devt_attr = attr;
        }
 
-       class_device_add_attrs(class_dev);
+       error = class_device_add_attrs(class_dev);
+       if (error)
+               goto out5;
+
        if (class_dev->dev) {
-               class_name = make_class_name(class_dev);
-               sysfs_create_link(&class_dev->kobj,
-                                 &class_dev->dev->kobj, "device");
-               sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
-                                 class_name);
+               class_name = make_class_name(class_dev->class->name,
+                                            &class_dev->kobj);
+               error = sysfs_create_link(&class_dev->kobj,
+                                         &class_dev->dev->kobj, "device");
+               if (error)
+                       goto out6;
+               error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
+                                         class_name);
+               if (error)
+                       goto out7;
        }
 
-       class_device_add_groups(class_dev);
+       error = class_device_add_groups(class_dev);
+       if (error)
+               goto out8;
 
        kobject_uevent(&class_dev->kobj, KOBJ_ADD);
 
@@ -601,11 +622,28 @@ int class_device_add(struct class_device *class_dev)
        }
        up(&parent_class->sem);
 
- register_done:
-       if (error) {
-               class_put(parent_class);
+       goto out1;
+
+ out8:
+       if (class_dev->dev)
+               sysfs_remove_link(&class_dev->kobj, class_name);
+ out7:
+       if (class_dev->dev)
+               sysfs_remove_link(&class_dev->kobj, "device");
+ out6:
+       class_device_remove_attrs(class_dev);
+ out5:
+       if (class_dev->devt_attr)
+               class_device_remove_file(class_dev, class_dev->devt_attr);
+ out4:
+       class_device_remove_file(class_dev, &class_dev->uevent_attr);
+ out3:
+       kobject_del(&class_dev->kobj);
+ out2:
+       if(parent_class_dev)
                class_device_put(parent_class_dev);
-       }
+       class_put(parent_class);
+ out1:
        class_device_put(class_dev);
        kfree(class_name);
        return error;
@@ -695,10 +733,12 @@ void class_device_del(struct class_device *class_dev)
        }
 
        if (class_dev->dev) {
-               class_name = make_class_name(class_dev);
+               class_name = make_class_name(class_dev->class->name,
+                                            &class_dev->kobj);
                sysfs_remove_link(&class_dev->kobj, "device");
                sysfs_remove_link(&class_dev->dev->kobj, class_name);
        }
+       sysfs_remove_link(&class_dev->kobj, "subsystem");
        class_device_remove_file(class_dev, &class_dev->uevent_attr);
        if (class_dev->devt_attr)
                class_device_remove_file(class_dev, class_dev->devt_attr);
@@ -760,14 +800,16 @@ int class_device_rename(struct class_device *class_dev, char *new_name)
                 new_name);
 
        if (class_dev->dev)
-               old_class_name = make_class_name(class_dev);
+               old_class_name = make_class_name(class_dev->class->name,
+                                                &class_dev->kobj);
 
        strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
 
        error = kobject_rename(&class_dev->kobj, new_name);
 
        if (class_dev->dev) {
-               new_class_name = make_class_name(class_dev);
+               new_class_name = make_class_name(class_dev->class->name,
+                                                &class_dev->kobj);
                sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
                                  new_class_name);
                sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
@@ -858,8 +900,6 @@ EXPORT_SYMBOL_GPL(class_create_file);
 EXPORT_SYMBOL_GPL(class_remove_file);
 EXPORT_SYMBOL_GPL(class_register);
 EXPORT_SYMBOL_GPL(class_unregister);
-EXPORT_SYMBOL_GPL(class_get);
-EXPORT_SYMBOL_GPL(class_put);
 EXPORT_SYMBOL_GPL(class_create);
 EXPORT_SYMBOL_GPL(class_destroy);
 
index 6b355bd7816d8fcffea570047396eb28323f6771..d0f84ff78776f6c6765ea297cdda587cbd1b238c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/kdev_t.h>
 
 #include <asm/semaphore.h>
 
@@ -28,6 +29,22 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
  * sysfs bindings for devices.
  */
 
+/**
+ * dev_driver_string - Return a device's driver name, if at all possible
+ * @dev: struct device to get the name of
+ *
+ * Will return the device's driver's name if it is bound to a device.  If
+ * the device is not bound to a device, it will return the name of the bus
+ * it is attached to.  If it is not attached to a bus either, an empty
+ * string will be returned.
+ */
+const char *dev_driver_string(struct device *dev)
+{
+       return dev->driver ? dev->driver->name :
+                       (dev->bus ? dev->bus->name : "");
+}
+EXPORT_SYMBOL_GPL(dev_driver_string);
+
 #define to_dev(obj) container_of(obj, struct device, kobj)
 #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 
@@ -98,6 +115,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
                struct device *dev = to_dev(kobj);
                if (dev->bus)
                        return 1;
+               if (dev->class)
+                       return 1;
        }
        return 0;
 }
@@ -106,7 +125,11 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
 {
        struct device *dev = to_dev(kobj);
 
-       return dev->bus->name;
+       if (dev->bus)
+               return dev->bus->name;
+       if (dev->class)
+               return dev->class->name;
+       return NULL;
 }
 
 static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
@@ -117,6 +140,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
        int length = 0;
        int retval = 0;
 
+       /* add the major/minor if present */
+       if (MAJOR(dev->devt)) {
+               add_uevent_var(envp, num_envp, &i,
+                              buffer, buffer_size, &length,
+                              "MAJOR=%u", MAJOR(dev->devt));
+               add_uevent_var(envp, num_envp, &i,
+                              buffer, buffer_size, &length,
+                              "MINOR=%u", MINOR(dev->devt));
+       }
+
        /* add bus name of physical device */
        if (dev->bus)
                add_uevent_var(envp, num_envp, &i,
@@ -161,6 +194,12 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       return print_dev_t(buf, dev->devt);
+}
+
 /*
  *     devices_subsys - structure to be registered with kobject core.
  */
@@ -231,6 +270,7 @@ void device_initialize(struct device *dev)
        klist_init(&dev->klist_children, klist_children_get,
                   klist_children_put);
        INIT_LIST_HEAD(&dev->dma_pools);
+       INIT_LIST_HEAD(&dev->node);
        init_MUTEX(&dev->sem);
        device_init_wakeup(dev, 0);
 }
@@ -249,6 +289,7 @@ void device_initialize(struct device *dev)
 int device_add(struct device *dev)
 {
        struct device *parent = NULL;
+       char *class_name = NULL;
        int error = -EINVAL;
 
        dev = get_device(dev);
@@ -274,11 +315,44 @@ int device_add(struct device *dev)
        dev->uevent_attr.store = store_uevent;
        device_create_file(dev, &dev->uevent_attr);
 
-       kobject_uevent(&dev->kobj, KOBJ_ADD);
+       if (MAJOR(dev->devt)) {
+               struct device_attribute *attr;
+               attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+               if (!attr) {
+                       error = -ENOMEM;
+                       goto PMError;
+               }
+               attr->attr.name = "dev";
+               attr->attr.mode = S_IRUGO;
+               if (dev->driver)
+                       attr->attr.owner = dev->driver->owner;
+               attr->show = show_dev;
+               error = device_create_file(dev, attr);
+               if (error) {
+                       kfree(attr);
+                       goto attrError;
+               }
+
+               dev->devt_attr = attr;
+       }
+
+       if (dev->class) {
+               sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,
+                                 "subsystem");
+               sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
+                                 dev->bus_id);
+
+               sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
+               class_name = make_class_name(dev->class->name, &dev->kobj);
+               sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+       }
+
        if ((error = device_pm_add(dev)))
                goto PMError;
        if ((error = bus_add_device(dev)))
                goto BusError;
+       kobject_uevent(&dev->kobj, KOBJ_ADD);
+       bus_attach_device(dev);
        if (parent)
                klist_add_tail(&dev->knode_parent, &parent->klist_children);
 
@@ -286,11 +360,17 @@ int device_add(struct device *dev)
        if (platform_notify)
                platform_notify(dev);
  Done:
+       kfree(class_name);
        put_device(dev);
        return error;
  BusError:
        device_pm_remove(dev);
  PMError:
+       if (dev->devt_attr) {
+               device_remove_file(dev, dev->devt_attr);
+               kfree(dev->devt_attr);
+       }
+ attrError:
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
        kobject_del(&dev->kobj);
  Error:
@@ -362,9 +442,20 @@ void put_device(struct device * dev)
 void device_del(struct device * dev)
 {
        struct device * parent = dev->parent;
+       char *class_name = NULL;
 
        if (parent)
                klist_del(&dev->knode_parent);
+       if (dev->devt_attr)
+               device_remove_file(dev, dev->devt_attr);
+       if (dev->class) {
+               sysfs_remove_link(&dev->kobj, "subsystem");
+               sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id);
+               class_name = make_class_name(dev->class->name, &dev->kobj);
+               sysfs_remove_link(&dev->kobj, "device");
+               sysfs_remove_link(&dev->parent->kobj, class_name);
+               kfree(class_name);
+       }
        device_remove_file(dev, &dev->uevent_attr);
 
        /* Notify the platform of the removal, in case they
@@ -449,3 +540,105 @@ EXPORT_SYMBOL_GPL(put_device);
 
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
+
+
+static void device_create_release(struct device *dev)
+{
+       pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id);
+       kfree(dev);
+}
+
+/**
+ * device_create - creates a device and registers it with sysfs
+ * @cs: pointer to the struct class that this device should be registered to.
+ * @parent: pointer to the parent struct device of this new device, if any.
+ * @dev: the dev_t for the char device to be added.
+ * @fmt: string for the class device's name
+ *
+ * This function can be used by char device classes.  A struct
+ * device will be created in sysfs, registered to the specified
+ * class.
+ * A "dev" file will be created, showing the dev_t for the device, if
+ * the dev_t is not 0,0.
+ * If a pointer to a parent struct device is passed in, the newly
+ * created struct device will be a child of that device in sysfs.  The
+ * pointer to the struct device will be returned from the call.  Any
+ * further sysfs files that might be required can be created using this
+ * pointer.
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
+struct device *device_create(struct class *class, struct device *parent,
+                            dev_t devt, char *fmt, ...)
+{
+       va_list args;
+       struct device *dev = NULL;
+       int retval = -ENODEV;
+
+       if (class == NULL || IS_ERR(class))
+               goto error;
+       if (parent == NULL) {
+               printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__);
+               goto error;
+       }
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       dev->devt = devt;
+       dev->class = class;
+       dev->parent = parent;
+       dev->release = device_create_release;
+
+       va_start(args, fmt);
+       vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
+       va_end(args);
+       retval = device_register(dev);
+       if (retval)
+               goto error;
+
+       /* tie the class to the device */
+       down(&class->sem);
+       list_add_tail(&dev->node, &class->devices);
+       up(&class->sem);
+
+       return dev;
+
+error:
+       kfree(dev);
+       return ERR_PTR(retval);
+}
+EXPORT_SYMBOL_GPL(device_create);
+
+/**
+ * device_destroy - removes a device that was created with device_create()
+ * @class: the pointer to the struct class that this device was registered * with.
+ * @dev: the dev_t of the device that was previously registered.
+ *
+ * This call unregisters and cleans up a class device that was created with a
+ * call to class_device_create()
+ */
+void device_destroy(struct class *class, dev_t devt)
+{
+       struct device *dev = NULL;
+       struct device *dev_tmp;
+
+       down(&class->sem);
+       list_for_each_entry(dev_tmp, &class->devices, node) {
+               if (dev_tmp->devt == devt) {
+                       dev = dev_tmp;
+                       break;
+               }
+       }
+       up(&class->sem);
+
+       if (dev) {
+               list_del_init(&dev->node);
+               device_unregister(dev);
+       }
+}
+EXPORT_SYMBOL_GPL(device_destroy);
index 0c99ae6a340728bb55efc503aca6b9bb92e26860..5d6c011183f5b7259297276b251f1648580421c7 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include <linux/firmware.h>
 #include "base.h"
@@ -36,7 +36,7 @@ static int loading_timeout = 10;      /* In seconds */
 
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
-static DECLARE_MUTEX(fw_lock);
+static DEFINE_MUTEX(fw_lock);
 
 struct firmware_priv {
        char fw_id[FIRMWARE_NAME_MAX];
@@ -142,9 +142,9 @@ firmware_loading_store(struct class_device *class_dev,
 
        switch (loading) {
        case 1:
-               down(&fw_lock);
+               mutex_lock(&fw_lock);
                if (!fw_priv->fw) {
-                       up(&fw_lock);
+                       mutex_unlock(&fw_lock);
                        break;
                }
                vfree(fw_priv->fw->data);
@@ -152,7 +152,7 @@ firmware_loading_store(struct class_device *class_dev,
                fw_priv->fw->size = 0;
                fw_priv->alloc_size = 0;
                set_bit(FW_STATUS_LOADING, &fw_priv->status);
-               up(&fw_lock);
+               mutex_unlock(&fw_lock);
                break;
        case 0:
                if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
@@ -185,7 +185,7 @@ firmware_data_read(struct kobject *kobj,
        struct firmware *fw;
        ssize_t ret_count = count;
 
-       down(&fw_lock);
+       mutex_lock(&fw_lock);
        fw = fw_priv->fw;
        if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
                ret_count = -ENODEV;
@@ -200,7 +200,7 @@ firmware_data_read(struct kobject *kobj,
 
        memcpy(buffer, fw->data + offset, ret_count);
 out:
-       up(&fw_lock);
+       mutex_unlock(&fw_lock);
        return ret_count;
 }
 
@@ -253,7 +253,7 @@ firmware_data_write(struct kobject *kobj,
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
 
-       down(&fw_lock);
+       mutex_lock(&fw_lock);
        fw = fw_priv->fw;
        if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
                retval = -ENODEV;
@@ -268,7 +268,7 @@ firmware_data_write(struct kobject *kobj,
        fw->size = max_t(size_t, offset + count, fw->size);
        retval = count;
 out:
-       up(&fw_lock);
+       mutex_unlock(&fw_lock);
        return retval;
 }
 
@@ -436,14 +436,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
        } else
                wait_for_completion(&fw_priv->completion);
 
-       down(&fw_lock);
+       mutex_lock(&fw_lock);
        if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
                retval = -ENOENT;
                release_firmware(fw_priv->fw);
                *firmware_p = NULL;
        }
        fw_priv->fw = NULL;
-       up(&fw_lock);
+       mutex_unlock(&fw_lock);
        class_device_unregister(class_dev);
        goto out;
 
diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c
new file mode 100644 (file)
index 0000000..0c85e9d
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * hypervisor.c - /sys/hypervisor subsystem.
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/kobject.h>
+#include <linux/device.h>
+
+#include "base.h"
+
+decl_subsys(hypervisor, NULL, NULL);
+EXPORT_SYMBOL_GPL(hypervisor_subsys);
+
+int __init hypervisor_init(void)
+{
+       return subsystem_register(&hypervisor_subsys);
+}
index c648914b9cde8b37be242c46f3c85429941fdc8f..37138154f9e824b353f322022ba8c41017ae3c3e 100644 (file)
@@ -27,6 +27,7 @@ void __init driver_init(void)
        buses_init();
        classes_init();
        firmware_init();
+       hypervisor_init();
 
        /* These are also core pieces, but must come after the
         * core core pieces.
diff --git a/drivers/base/isa.c b/drivers/base/isa.c
new file mode 100644 (file)
index 0000000..d222239
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * ISA bus.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/isa.h>
+
+static struct device isa_bus = {
+       .bus_id         = "isa"
+};
+
+struct isa_dev {
+       struct device dev;
+       struct device *next;
+       unsigned int id;
+};
+
+#define to_isa_dev(x) container_of((x), struct isa_dev, dev)
+
+static int isa_bus_match(struct device *dev, struct device_driver *driver)
+{
+       struct isa_driver *isa_driver = to_isa_driver(driver);
+
+       if (dev->platform_data == isa_driver) {
+               if (!isa_driver->match ||
+                       isa_driver->match(dev, to_isa_dev(dev)->id))
+                       return 1;
+               dev->platform_data = NULL;
+       }
+       return 0;
+}
+
+static int isa_bus_probe(struct device *dev)
+{
+       struct isa_driver *isa_driver = dev->platform_data;
+
+       if (isa_driver->probe)
+               return isa_driver->probe(dev, to_isa_dev(dev)->id);
+
+       return 0;
+}
+
+static int isa_bus_remove(struct device *dev)
+{
+       struct isa_driver *isa_driver = dev->platform_data;
+
+       if (isa_driver->remove)
+               return isa_driver->remove(dev, to_isa_dev(dev)->id);
+
+       return 0;
+}
+
+static void isa_bus_shutdown(struct device *dev)
+{
+       struct isa_driver *isa_driver = dev->platform_data;
+
+       if (isa_driver->shutdown)
+               isa_driver->shutdown(dev, to_isa_dev(dev)->id);
+}
+
+static int isa_bus_suspend(struct device *dev, pm_message_t state)
+{
+       struct isa_driver *isa_driver = dev->platform_data;
+
+       if (isa_driver->suspend)
+               return isa_driver->suspend(dev, to_isa_dev(dev)->id, state);
+
+       return 0;
+}
+
+static int isa_bus_resume(struct device *dev)
+{
+       struct isa_driver *isa_driver = dev->platform_data;
+
+       if (isa_driver->resume)
+               return isa_driver->resume(dev, to_isa_dev(dev)->id);
+
+       return 0;
+}
+
+static struct bus_type isa_bus_type = {
+       .name           = "isa",
+       .match          = isa_bus_match,
+       .probe          = isa_bus_probe,
+       .remove         = isa_bus_remove,
+       .shutdown       = isa_bus_shutdown,
+       .suspend        = isa_bus_suspend,
+       .resume         = isa_bus_resume
+};
+
+static void isa_dev_release(struct device *dev)
+{
+       kfree(to_isa_dev(dev));
+}
+
+void isa_unregister_driver(struct isa_driver *isa_driver)
+{
+       struct device *dev = isa_driver->devices;
+
+       while (dev) {
+               struct device *tmp = to_isa_dev(dev)->next;
+               device_unregister(dev);
+               dev = tmp;
+       }
+       driver_unregister(&isa_driver->driver);
+}
+EXPORT_SYMBOL_GPL(isa_unregister_driver);
+
+int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev)
+{
+       int error;
+       unsigned int id;
+
+       isa_driver->driver.bus  = &isa_bus_type;
+       isa_driver->devices     = NULL;
+
+       error = driver_register(&isa_driver->driver);
+       if (error)
+               return error;
+
+       for (id = 0; id < ndev; id++) {
+               struct isa_dev *isa_dev;
+
+               isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL);
+               if (!isa_dev) {
+                       error = -ENOMEM;
+                       break;
+               }
+
+               isa_dev->dev.parent     = &isa_bus;
+               isa_dev->dev.bus        = &isa_bus_type;
+
+               snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u",
+                               isa_driver->driver.name, id);
+
+               isa_dev->dev.platform_data      = isa_driver;
+               isa_dev->dev.release            = isa_dev_release;
+               isa_dev->id                     = id;
+
+               error = device_register(&isa_dev->dev);
+               if (error) {
+                       put_device(&isa_dev->dev);
+                       break;
+               }
+
+               if (isa_dev->dev.platform_data) {
+                       isa_dev->next = isa_driver->devices;
+                       isa_driver->devices = &isa_dev->dev;
+               } else
+                       device_unregister(&isa_dev->dev);
+       }
+
+       if (!error && !isa_driver->devices)
+               error = -ENODEV;
+
+       if (error)
+               isa_unregister_driver(isa_driver);
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(isa_register_driver);
+
+static int __init isa_bus_init(void)
+{
+       int error;
+
+       error = bus_register(&isa_bus_type);
+       if (!error) {
+               error = device_register(&isa_bus);
+               if (error)
+                       bus_unregister(&isa_bus_type);
+       }
+       return error;
+}
+
+device_initcall(isa_bus_init);
index 83f5c5984d1a96da2aab912b3ab936e11f2854d4..2b8755db76c6e65f48b7784cb463d6a213238453 100644 (file)
@@ -275,7 +275,7 @@ int platform_device_add(struct platform_device *pdev)
        pr_debug("Registering platform device '%s'. Parent at %s\n",
                 pdev->dev.bus_id, pdev->dev.parent->bus_id);
 
-       ret = device_register(&pdev->dev);
+       ret = device_add(&pdev->dev);
        if (ret == 0)
                return ret;
 
@@ -452,6 +452,37 @@ void platform_driver_unregister(struct platform_driver *drv)
 EXPORT_SYMBOL_GPL(platform_driver_unregister);
 
 
+/* modalias support enables more hands-off userspace setup:
+ * (a) environment variable lets new-style hotplug events work once system is
+ *     fully running:  "modprobe $MODALIAS"
+ * (b) sysfs attribute lets new-style coldplug recover from hotplug events
+ *     mishandled before system is fully running:  "modprobe $(cat modalias)"
+ */
+static ssize_t
+modalias_show(struct device *dev, struct device_attribute *a, char *buf)
+{
+       struct platform_device  *pdev = to_platform_device(dev);
+       int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute platform_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_NULL,
+};
+
+static int platform_uevent(struct device *dev, char **envp, int num_envp,
+               char *buffer, int buffer_size)
+{
+       struct platform_device  *pdev = to_platform_device(dev);
+
+       envp[0] = buffer;
+       snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+       return 0;
+}
+
+
 /**
  *     platform_match - bind platform device to platform driver.
  *     @dev:   device.
@@ -496,7 +527,9 @@ static int platform_resume(struct device * dev)
 
 struct bus_type platform_bus_type = {
        .name           = "platform",
+       .dev_attrs      = platform_dev_attrs,
        .match          = platform_match,
+       .uevent         = platform_uevent,
        .suspend        = platform_suspend,
        .resume         = platform_resume,
 };
index c0219ad94aca123768afb8f58afe7a214e1ce819..ceeeba2c56c7a426825b9dd982b6039dd8b99f3f 100644 (file)
@@ -4,3 +4,6 @@ obj-$(CONFIG_PM)        += main.o suspend.o resume.o runtime.o sysfs.o
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
+ifeq ($(CONFIG_PM_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
index 2a769cc6f5f9f8181580b6657c0d0625e9c937dd..1a1fe43a30570cec1054b446b065389cd8197fee 100644 (file)
  * lists. This way, the ancestors will be accessed before their descendents.
  */
 
+static inline char *suspend_verb(u32 event)
+{
+       switch (event) {
+       case PM_EVENT_SUSPEND:  return "suspend";
+       case PM_EVENT_FREEZE:   return "freeze";
+       default:                return "(unknown suspend event)";
+       }
+}
+
 
 /**
  *     suspend_device - Save state of one device.
@@ -57,7 +66,13 @@ int suspend_device(struct device * dev, pm_message_t state)
        dev->power.prev_state = dev->power.power_state;
 
        if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
-               dev_dbg(dev, "suspending\n");
+               dev_dbg(dev, "%s%s\n",
+                       suspend_verb(state.event),
+                       ((state.event == PM_EVENT_SUSPEND)
+                                       && device_may_wakeup(dev))
+                               ? ", may wakeup"
+                               : ""
+                       );
                error = dev->bus->suspend(dev, state);
                suspend_report_result(dev->bus->suspend, error);
        }
index 6fc23ab127bd52abd01f10eb55136a7c3057a12b..6858178b3aff8d28e727e2d487adf289817324bd 100644 (file)
@@ -80,10 +80,59 @@ void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a)
 EXPORT_SYMBOL_GPL(sysdev_create_file);
 EXPORT_SYMBOL_GPL(sysdev_remove_file);
 
+#define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj)
+#define to_sysdev_class_attr(a) container_of(a, \
+       struct sysdev_class_attribute, attr)
+
+static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
+                                char *buffer)
+{
+       struct sysdev_class * class = to_sysdev_class(kobj);
+       struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
+
+       if (class_attr->show)
+               return class_attr->show(class, buffer);
+       return -EIO;
+}
+
+static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,
+                                 const char *buffer, size_t count)
+{
+       struct sysdev_class * class = to_sysdev_class(kobj);
+       struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr);
+
+       if (class_attr->store)
+               return class_attr->store(class, buffer, count);
+       return -EIO;
+}
+
+static struct sysfs_ops sysfs_class_ops = {
+       .show   = sysdev_class_show,
+       .store  = sysdev_class_store,
+};
+
+static struct kobj_type ktype_sysdev_class = {
+       .sysfs_ops      = &sysfs_class_ops,
+};
+
+int sysdev_class_create_file(struct sysdev_class *c,
+                            struct sysdev_class_attribute *a)
+{
+       return sysfs_create_file(&c->kset.kobj, &a->attr);
+}
+EXPORT_SYMBOL_GPL(sysdev_class_create_file);
+
+void sysdev_class_remove_file(struct sysdev_class *c,
+                             struct sysdev_class_attribute *a)
+{
+       sysfs_remove_file(&c->kset.kobj, &a->attr);
+}
+EXPORT_SYMBOL_GPL(sysdev_class_remove_file);
+
 /*
  * declare system_subsys
  */
-static decl_subsys(system, &ktype_sysdev, NULL);
+static decl_subsys(system, &ktype_sysdev_class, NULL);
 
 int sysdev_class_register(struct sysdev_class * cls)
 {
index 1319d8f20640505b69ebc6a37c3f9b435910ee0e..25c3c4a5da813ed27e2ff4541e543079b842b871 100644 (file)
@@ -3237,6 +3237,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                disk->fops = &cciss_fops;
                disk->queue = q;
                disk->private_data = drv;
+               disk->driverfs_dev = &pdev->dev;
                /* we must register the controller even if no disks exist */
                /* this is for the online array utilities */
                if(!drv->heads && j)
index c688c25992e44b0a914624735c448e7e7abb1429..60e9a9457c6b0789b7b29e0e8c36e148b9424653 100644 (file)
  * TODO (sorted by decreasing priority)
  *  -- set readonly flag for CDs, set removable flag for CF readers
  *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
- *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
  *  -- verify the 13 conditions and do bulk resets
- *  -- kill last_pipe and simply do two-state clearing on both pipes
  *  -- highmem
  *  -- move top_sense and work_bcs into separate allocations (if they survive)
  *     for cache purists and esoteric architectures.
  *  -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ?
  *  -- prune comments, they are too volumnous
- *  -- Exterminate P3 printks
  *  -- Resove XXX's
- *  -- Redo "benh's retries", perhaps have spin-up code to handle them. V:D=?
  *  -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring.
  */
 #include <linux/kernel.h>
@@ -180,7 +176,6 @@ struct ub_dev;
 #define UB_DIR_ILLEGAL2        2
 #define UB_DIR_WRITE   3
 
-/* P3 */
 #define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
                         (((c)==UB_DIR_READ)? 'r': 'n'))
 
@@ -669,8 +664,9 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
         */
        n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]);
        if (n_elem < 0) {
+               /* Impossible, because blk_rq_map_sg should not hit ENOMEM. */
                printk(KERN_INFO "%s: failed request map (%d)\n",
-                   lun->name, n_elem); /* P3 */
+                   lun->name, n_elem);
                goto drop;
        }
        if (n_elem > UB_MAX_REQ_SG) {   /* Paranoia */
@@ -824,7 +820,9 @@ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
        if (urq->current_try >= 3)
                return -EIO;
        urq->current_try++;
-       /* P3 */ printk("%s: dir %c len/act %d/%d "
+
+       /* Remove this if anyone complains of flooding. */
+       printk(KERN_DEBUG "%s: dir %c len/act %d/%d "
            "[sense %x %02x %02x] retry %d\n",
            sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len,
            cmd->key, cmd->asc, cmd->ascq, urq->current_try);
@@ -1241,8 +1239,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                         * to check. But it's not all right if the device
                         * counts disagree with our counts.
                         */
-                       /* P3 */ printk("%s: resid %d len %d act %d\n",
-                           sc->name, len, cmd->len, cmd->act_len);
                        goto Bad_End;
                }
 
@@ -1253,7 +1249,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        ub_state_sense(sc, cmd);
                        return;
                case US_BULK_STAT_PHASE:
-                       /* P3 */ printk("%s: status PHASE\n", sc->name);
                        goto Bad_End;
                default:
                        printk(KERN_INFO "%s: unknown CSW status 0x%x\n",
@@ -1568,16 +1563,14 @@ static void ub_reset_task(void *arg)
        }
 
        if (atomic_read(&sc->poison)) {
-               printk(KERN_NOTICE "%s: Not resetting disconnected device\n",
-                   sc->name); /* P3 This floods. Remove soon. XXX */
+               ;
        } else if ((sc->reset & 1) == 0) {
                ub_sync_reset(sc);
                msleep(700);    /* usb-storage sleeps 6s (!) */
                ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
                ub_probe_clear_stall(sc, sc->send_bulk_pipe);
        } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
-               printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
-                   sc->name); /* P3 This floods. Remove soon. XXX */
+               ;
        } else {
                if ((lkr = usb_lock_device_for_reset(sc->dev, sc->intf)) < 0) {
                        printk(KERN_NOTICE
@@ -1651,15 +1644,11 @@ static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
 static int ub_bd_open(struct inode *inode, struct file *filp)
 {
        struct gendisk *disk = inode->i_bdev->bd_disk;
-       struct ub_lun *lun;
-       struct ub_dev *sc;
+       struct ub_lun *lun = disk->private_data;
+       struct ub_dev *sc = lun->udev;
        unsigned long flags;
        int rc;
 
-       if ((lun = disk->private_data) == NULL)
-               return -ENXIO;
-       sc = lun->udev;
-
        spin_lock_irqsave(&ub_lock, flags);
        if (atomic_read(&sc->poison)) {
                spin_unlock_irqrestore(&ub_lock, flags);
@@ -1823,10 +1812,8 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
        rc = ub_submit_scsi(sc, cmd);
        spin_unlock_irqrestore(sc->lock, flags);
 
-       if (rc != 0) {
-               printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */
+       if (rc != 0)
                goto err_submit;
-       }
 
        wait_for_completion(&compl);
 
@@ -1884,20 +1871,16 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
        rc = ub_submit_scsi(sc, cmd);
        spin_unlock_irqrestore(sc->lock, flags);
 
-       if (rc != 0) {
-               printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */
+       if (rc != 0)
                goto err_submit;
-       }
 
        wait_for_completion(&compl);
 
        if (cmd->error != 0) {
-               printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */
                rc = -EIO;
                goto err_read;
        }
        if (cmd->act_len != 8) {
-               printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */
                rc = -EIO;
                goto err_read;
        }
@@ -1911,7 +1894,6 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
        case 2048:      shift = 2;      break;
        case 4096:      shift = 3;      break;
        default:
-               printk("ub: Bad sector size %u\n", bsize); /* P3 */
                rc = -EDOM;
                goto err_inv_bsize;
        }
@@ -2023,17 +2005,8 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
        sc->work_urb.error_count = 0;
        sc->work_urb.status = 0;
 
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
-               if (rc == -EPIPE) {
-                       printk("%s: Stall submitting GetMaxLUN, using 1 LUN\n",
-                            sc->name); /* P3 */
-               } else {
-                       printk(KERN_NOTICE
-                            "%s: Unable to submit GetMaxLUN (%d)\n",
-                            sc->name, rc);
-               }
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0)
                goto err_submit;
-       }
 
        init_timer(&timer);
        timer.function = ub_probe_timeout;
@@ -2046,21 +2019,10 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
        del_timer_sync(&timer);
        usb_kill_urb(&sc->work_urb);
 
-       if ((rc = sc->work_urb.status) < 0) {
-               if (rc == -EPIPE) {
-                       printk("%s: Stall at GetMaxLUN, using 1 LUN\n",
-                            sc->name); /* P3 */
-               } else {
-                       printk(KERN_NOTICE
-                            "%s: Error at GetMaxLUN (%d)\n",
-                            sc->name, rc);
-               }
+       if ((rc = sc->work_urb.status) < 0)
                goto err_io;
-       }
 
        if (sc->work_urb.actual_length != 1) {
-               printk("%s: GetMaxLUN returned %d bytes\n", sc->name,
-                   sc->work_urb.actual_length); /* P3 */
                nluns = 0;
        } else {
                if ((nluns = *p) == 55) {
@@ -2071,8 +2033,6 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
                        if (nluns > UB_MAX_LUNS)
                                nluns = UB_MAX_LUNS;
                }
-               printk("%s: GetMaxLUN returned %d, using %d LUNs\n", sc->name,
-                   *p, nluns); /* P3 */
        }
 
        kfree(p);
@@ -2270,7 +2230,7 @@ static int ub_probe(struct usb_interface *intf,
         * has to succeed, so we clear checks with an additional one here.
         * In any case it's not our business how revaliadation is implemented.
         */
-       for (i = 0; i < 3; i++) {       /* Retries for benh's key */
+       for (i = 0; i < 3; i++) {  /* Retries for the schwag key from KS'04 */
                if ((rc = ub_sync_tur(sc, NULL)) <= 0) break;
                if (rc != 0x6) break;
                msleep(10);
@@ -2318,7 +2278,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
                goto err_id;
 
        lun->udev = sc;
-       list_add(&lun->link, &sc->luns);
 
        snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
            lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
@@ -2331,7 +2290,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL)
                goto err_diskalloc;
 
-       lun->disk = disk;
        sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
        sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
        disk->major = UB_MAJOR;
@@ -2353,7 +2311,9 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        blk_queue_max_sectors(q, UB_MAX_SECTORS);
        blk_queue_hardsect_size(q, lun->capacity.bsize);
 
+       lun->disk = disk;
        q->queuedata = lun;
+       list_add(&lun->link, &sc->luns);
 
        set_capacity(disk, lun->capacity.nsec);
        if (lun->removable)
@@ -2366,7 +2326,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
 err_blkqinit:
        put_disk(disk);
 err_diskalloc:
-       list_del(&lun->link);
        ub_id_put(lun->id);
 err_id:
        kfree(lun);
@@ -2379,7 +2338,6 @@ static void ub_disconnect(struct usb_interface *intf)
        struct ub_dev *sc = usb_get_intfdata(intf);
        struct list_head *p;
        struct ub_lun *lun;
-       struct gendisk *disk;
        unsigned long flags;
 
        /*
@@ -2435,9 +2393,7 @@ static void ub_disconnect(struct usb_interface *intf)
         */
        list_for_each (p, &sc->luns) {
                lun = list_entry(p, struct ub_lun, link);
-               disk = lun->disk;
-               if (disk->flags & GENHD_FL_UP)
-                       del_gendisk(disk);
+               del_gendisk(lun->disk);
                /*
                 * I wish I could do:
                 *    set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
index 7c88c060a9e6b3ab908660b6676aef4423488a35..46685a540772908817b10fbae775fe8099ab2bb8 100644 (file)
@@ -1,7 +1,6 @@
 config AGP
-       tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU
+       tristate "/dev/agpgart (AGP Support)"
        depends on ALPHA || IA64 || PPC || X86
-       default y if GART_IOMMU
        ---help---
          AGP (Accelerated Graphics Port) is a bus system mainly used to
          connect graphics cards to the rest of the system.
index a88b94a82b140f42b24d68409f651392805e0465..8b2a5996986819b62eccb4ffdb436d1d3903521a 100644 (file)
@@ -2961,12 +2961,14 @@ static struct class *tty_class;
  *     This field is optional, if there is no known struct device for this
  *     tty device it can be set to NULL safely.
  *
+ * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error).
+ *
  * This call is required to be made to register an individual tty device if
  * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set.  If that
  * bit is not set, this function should not be called.
  */
-void tty_register_device(struct tty_driver *driver, unsigned index,
-                        struct device *device)
+struct class_device *tty_register_device(struct tty_driver *driver,
+                                        unsigned index, struct device *device)
 {
        char name[64];
        dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
@@ -2974,7 +2976,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index,
        if (index >= driver->num) {
                printk(KERN_ERR "Attempt to register invalid tty line number "
                       " (%d).\n", index);
-               return;
+               return ERR_PTR(-EINVAL);
        }
 
        devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
@@ -2984,7 +2986,8 @@ void tty_register_device(struct tty_driver *driver, unsigned index,
                pty_line_name(driver, index, name);
        else
                tty_line_name(driver, index, name);
-       class_device_create(tty_class, NULL, dev, device, "%s", name);
+
+       return class_device_create(tty_class, NULL, dev, device, "%s", name);
 }
 
 /**
index e55767b2ccd3cc8d3f8fab741aec3e37a900b8bf..acb7e2656780274cd32fc8f4e170f234c3357bc4 100644 (file)
@@ -460,6 +460,9 @@ void gigaset_freecs(struct cardstate *cs)
 
        switch (cs->cs_init) {
        default:
+               /* clear device sysfs */
+               gigaset_free_dev_sysfs(cs);
+
                gigaset_if_free(cs);
 
                gig_dbg(DEBUG_INIT, "clearing hw");
@@ -699,6 +702,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
        cs->open_count = 0;
        cs->dev = NULL;
        cs->tty = NULL;
+       cs->class = NULL;
        cs->cidmode = cidmode != 0;
 
        //if(onechannel) { //FIXME
@@ -760,6 +764,9 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
 
        gigaset_if_init(cs);
 
+       /* set up device sysfs */
+       gigaset_init_dev_sysfs(cs);
+
        spin_lock_irqsave(&cs->lock, flags);
        cs->running = 1;
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -902,9 +909,6 @@ int gigaset_start(struct cardstate *cs)
 
        wait_event(cs->waitqueue, !cs->waiting);
 
-       /* set up device sysfs */
-       gigaset_init_dev_sysfs(cs);
-
        mutex_unlock(&cs->mutex);
        return 1;
 
@@ -969,9 +973,6 @@ void gigaset_stop(struct cardstate *cs)
                //FIXME
        }
 
-       /* clear device sysfs */
-       gigaset_free_dev_sysfs(cs);
-
        cleanup_cs(cs);
 
 exit:
index 22b9693f7c0a1623d007d77b492fb746cb32d157..8d63d822104fb53bad713ede2175016f800dba4f 100644 (file)
@@ -445,6 +445,7 @@ struct cardstate {
        struct gigaset_driver *driver;
        unsigned minor_index;
        struct device *dev;
+       struct class_device *class;
 
        const struct gigaset_ops *ops;
 
index 08e4c4eea14d985ecc186e99cc434f76b1334faf..74fd234956c8949ac2042161b9254456c87b0dda 100644 (file)
@@ -625,7 +625,14 @@ void gigaset_if_init(struct cardstate *cs)
                return;
 
        tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs);
-       tty_register_device(drv->tty, cs->minor_index, NULL);
+       cs->class = tty_register_device(drv->tty, cs->minor_index, NULL);
+
+       if (!IS_ERR(cs->class))
+               class_set_devdata(cs->class, cs);
+       else {
+               warn("could not register device to the tty subsystem");
+               cs->class = NULL;
+       }
 }
 
 void gigaset_if_free(struct cardstate *cs)
@@ -638,6 +645,7 @@ void gigaset_if_free(struct cardstate *cs)
 
        tasklet_disable(&cs->if_wake_tasklet);
        tasklet_kill(&cs->if_wake_tasklet);
+       cs->class = NULL;
        tty_unregister_device(drv->tty, cs->minor_index);
 }
 
index d267a636b53c63cbd9558b73e57474248d5f9a16..9ae3a7f3e7b3724982ce68bc75a37ae215766a6a 100644 (file)
 #include "gigaset.h"
 #include <linux/ctype.h>
 
-static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr,
-                           char *buf)
+static ssize_t show_cidmode(struct class_device *class, char *buf)
 {
        int ret;
        unsigned long flags;
-       struct cardstate *cs = dev_get_drvdata(dev);
+       struct cardstate *cs = class_get_devdata(class);
 
        spin_lock_irqsave(&cs->lock, flags);
        ret = sprintf(buf, "%u\n", cs->cidmode);
@@ -30,10 +29,10 @@ static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr,
        return ret;
 }
 
-static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
+static ssize_t set_cidmode(struct class_device *class,
                           const char *buf, size_t count)
 {
-       struct cardstate *cs = dev_get_drvdata(dev);
+       struct cardstate *cs = class_get_devdata(class);
        long int value;
        char *end;
 
@@ -65,18 +64,24 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode);
+static CLASS_DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode);
 
 /* free sysfs for device */
 void gigaset_free_dev_sysfs(struct cardstate *cs)
 {
+       if (!cs->class)
+               return;
+
        gig_dbg(DEBUG_INIT, "removing sysfs entries");
-       device_remove_file(cs->dev, &dev_attr_cidmode);
+       class_device_remove_file(cs->class, &class_device_attr_cidmode);
 }
 
 /* initialize sysfs for device */
 void gigaset_init_dev_sysfs(struct cardstate *cs)
 {
+       if (!cs->class)
+               return;
+
        gig_dbg(DEBUG_INIT, "setting up sysfs");
-       device_create_file(cs->dev, &dev_attr_cidmode);
+       class_device_create_file(cs->class, &class_device_attr_cidmode);
 }
index c11f5d46b11438e6454d4f15893152a257c64b2b..6f31ecc88843d16c7de882a8ee7e9dd28f538375 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/input.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #include "usbvideo.h"
 
index e1feb58bd6615675cbf89d23355efd63228be94f..1a2b9785e9986090e4ac5270b788411b48494421 100644 (file)
@@ -2120,7 +2120,7 @@ abort_linearize:
                goto drop;
        }
 
-       if (skb_linearize(skb, GFP_ATOMIC))
+       if (skb_linearize(skb))
                goto drop;
 
        mgp->tx_linearized++;
index 9b7d9769fdcc7179d8e95786b11f0a6f27d40ab4..c7123bf71c582bb1627ddc5116ce7723cab4eb1a 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_USB_MICROTEK)    += image/
 obj-$(CONFIG_USB_SERIAL)       += serial/
 
 obj-$(CONFIG_USB_AUERSWALD)    += misc/
+obj-$(CONFIG_USB_CY7C63)       += misc/
 obj-$(CONFIG_USB_CYTHERM)      += misc/
 obj-$(CONFIG_USB_EMI26)                += misc/
 obj-$(CONFIG_USB_EMI62)                += misc/
@@ -61,6 +62,7 @@ obj-$(CONFIG_USB_TEST)                += misc/
 obj-$(CONFIG_USB_USS720)       += misc/
 obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
 obj-$(CONFIG_USB_SISUSBVGA)    += misc/
+obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
 
 obj-$(CONFIG_USB_ATM)          += atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)   += atm/
index 546249843b8e5fe3613ada68e512484d5382d73b..a38701c742c3209cb0599faf558099b51a0db452 100644 (file)
@@ -1039,7 +1039,7 @@ static void usbatm_tasklet_schedule(unsigned long data)
        tasklet_schedule((struct tasklet_struct *) data);
 }
 
-static inline void usbatm_init_channel(struct usbatm_channel *channel)
+static void usbatm_init_channel(struct usbatm_channel *channel)
 {
        spin_lock_init(&channel->lock);
        INIT_LIST_HEAD(&channel->list);
index 42d6823b82b3d4efac2658bba02302c48f9baff1..70125c6d3be49d12fa9ae47947b65ab2cadcae0f 100644 (file)
@@ -20,7 +20,6 @@
  ******************************************************************************/
 
 #include <linux/module.h>
-#include <linux/netdevice.h>           /* FIXME: required by linux/etherdevice.h */
 #include <linux/etherdevice.h>         /* for random_ether_addr() */
 
 #include "usbatm.h"
index 6dd339f4c0fc52a933e3eb101f18bc88b94160f7..d41dc67ba4ccb74220dde9405a4df44ad86c93ce 100644 (file)
@@ -63,7 +63,7 @@
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
-#include <linux/usb_cdc.h>
+#include <linux/usb/cdc.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <linux/list.h>
@@ -127,8 +127,8 @@ static int acm_wb_alloc(struct acm *acm)
                        wb->use = 1;
                        return wbn;
                }
-               wbn = (wbn + 1) % ACM_NWB;
-               if (++i >= ACM_NWB)
+               wbn = (wbn + 1) % ACM_NW;
+               if (++i >= ACM_NW)
                        return -1;
        }
 }
@@ -142,10 +142,9 @@ static int acm_wb_is_avail(struct acm *acm)
 {
        int i, n;
 
-       n = 0;
-       for (i = 0; i < ACM_NWB; i++) {
-               if (!acm->wb[i].use)
-                       n++;
+       n = ACM_NW;
+       for (i = 0; i < ACM_NW; i++) {
+               n -= acm->wb[i].use;
        }
        return n;
 }
@@ -167,7 +166,7 @@ static void acm_write_done(struct acm *acm)
        acm->write_ready = 1;
        wbn = acm->write_current;
        acm_wb_free(acm, wbn);
-       acm->write_current = (wbn + 1) % ACM_NWB;
+       acm->write_current = (wbn + 1) % ACM_NW;
        spin_unlock_irqrestore(&acm->write_lock, flags);
 }
 
@@ -291,22 +290,32 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
        struct acm_rb *buf;
        struct acm_ru *rcv = urb->context;
        struct acm *acm = rcv->instance;
+       int status = urb->status;
        dbg("Entering acm_read_bulk with status %d\n", urb->status);
 
        if (!ACM_READY(acm))
                return;
 
-       if (urb->status)
-               dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status);
+       if (status)
+               dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
 
        buf = rcv->buffer;
        buf->size = urb->actual_length;
 
-       spin_lock(&acm->read_lock);
-       list_add_tail(&rcv->list, &acm->spare_read_urbs);
-       list_add_tail(&buf->list, &acm->filled_read_bufs);
-       spin_unlock(&acm->read_lock);
-
+       if (likely(status == 0)) {
+               spin_lock(&acm->read_lock);
+               list_add_tail(&rcv->list, &acm->spare_read_urbs);
+               list_add_tail(&buf->list, &acm->filled_read_bufs);
+               spin_unlock(&acm->read_lock);
+       } else {
+               /* we drop the buffer due to an error */
+               spin_lock(&acm->read_lock);
+               list_add_tail(&rcv->list, &acm->spare_read_urbs);
+               list_add(&buf->list, &acm->spare_read_bufs);
+               spin_unlock(&acm->read_lock);
+               /* nevertheless the tasklet must be kicked unconditionally
+               so the queue cannot dry up */
+       }
        tasklet_schedule(&acm->urb_task);
 }
 
@@ -464,10 +473,10 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
        INIT_LIST_HEAD(&acm->spare_read_urbs);
        INIT_LIST_HEAD(&acm->spare_read_bufs);
        INIT_LIST_HEAD(&acm->filled_read_bufs);
-       for (i = 0; i < ACM_NRU; i++) {
+       for (i = 0; i < acm->rx_buflimit; i++) {
                list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
        }
-       for (i = 0; i < ACM_NRB; i++) {
+       for (i = 0; i < acm->rx_buflimit; i++) {
                list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
        }
 
@@ -488,14 +497,15 @@ bail_out:
 
 static void acm_tty_unregister(struct acm *acm)
 {
-       int i;
+       int i,nr;
 
+       nr = acm->rx_buflimit;
        tty_unregister_device(acm_tty_driver, acm->minor);
        usb_put_intf(acm->control);
        acm_table[acm->minor] = NULL;
        usb_free_urb(acm->ctrlurb);
        usb_free_urb(acm->writeurb);
-       for (i = 0; i < ACM_NRU; i++)
+       for (i = 0; i < nr; i++)
                usb_free_urb(acm->ru[i].urb);
        kfree(acm);
 }
@@ -503,18 +513,19 @@ static void acm_tty_unregister(struct acm *acm)
 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 {
        struct acm *acm = tty->driver_data;
-       int i;
+       int i,nr;
 
        if (!acm || !acm->used)
                return;
 
+       nr = acm->rx_buflimit;
        mutex_lock(&open_mutex);
        if (!--acm->used) {
                if (acm->dev) {
                        acm_set_control(acm, acm->ctrlout = 0);
                        usb_kill_urb(acm->ctrlurb);
                        usb_kill_urb(acm->writeurb);
-                       for (i = 0; i < ACM_NRU; i++)
+                       for (i = 0; i < nr; i++)
                                usb_kill_urb(acm->ru[i].urb);
                } else
                        acm_tty_unregister(acm);
@@ -576,7 +587,7 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
        /*
         * This is inaccurate (overcounts), but it works.
         */
-       return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
+       return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;
 }
 
 static void acm_tty_throttle(struct tty_struct *tty)
@@ -712,7 +723,7 @@ static void acm_write_buffers_free(struct acm *acm)
        int i;
        struct acm_wb *wb;
 
-       for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+       for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
                usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
        }
 }
@@ -723,7 +734,7 @@ static int acm_write_buffers_alloc(struct acm *acm)
        int i;
        struct acm_wb *wb;
 
-       for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+       for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
                wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
                    &wb->dmah);
                if (!wb->buf) {
@@ -760,10 +771,14 @@ static int acm_probe (struct usb_interface *intf,
        int call_interface_num = -1;
        int data_interface_num;
        unsigned long quirks;
+       int num_rx_buf;
        int i;
 
-       /* handle quirks deadly to normal probing*/
+       /* normal quirks */
        quirks = (unsigned long)id->driver_info;
+       num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
+
+       /* handle quirks deadly to normal probing*/
        if (quirks == NO_UNION_NORMAL) {
                data_interface = usb_ifnum_to_if(usb_dev, 1);
                control_interface = usb_ifnum_to_if(usb_dev, 0);
@@ -900,7 +915,7 @@ skip_normal_probe:
        }
 
        ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
-       readsize = le16_to_cpu(epread->wMaxPacketSize)*2;
+       readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
        acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
        acm->control = control_interface;
        acm->data = data_interface;
@@ -909,6 +924,7 @@ skip_normal_probe:
        acm->ctrl_caps = ac_management_function;
        acm->ctrlsize = ctrlsize;
        acm->readsize = readsize;
+       acm->rx_buflimit = num_rx_buf;
        acm->urb_task.func = acm_rx_tasklet;
        acm->urb_task.data = (unsigned long) acm;
        INIT_WORK(&acm->work, acm_softint, acm);
@@ -935,7 +951,7 @@ skip_normal_probe:
                dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
                goto alloc_fail5;
        }
-       for (i = 0; i < ACM_NRU; i++) {
+       for (i = 0; i < num_rx_buf; i++) {
                struct acm_ru *rcv = &(acm->ru[i]);
 
                if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
@@ -946,10 +962,9 @@ skip_normal_probe:
                rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                rcv->instance = acm;
        }
-       for (i = 0; i < ACM_NRB; i++) {
+       for (i = 0; i < num_rx_buf; i++) {
                struct acm_rb *buf = &(acm->rb[i]);
 
-               // Using usb_buffer_alloc instead of kmalloc as Oliver suggested
                if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
                        dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
                        goto alloc_fail7;
@@ -988,9 +1003,9 @@ skip_normal_probe:
        return 0;
 
 alloc_fail7:
-       for (i = 0; i < ACM_NRB; i++)
+       for (i = 0; i < num_rx_buf; i++)
                usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
-       for (i = 0; i < ACM_NRU; i++)
+       for (i = 0; i < num_rx_buf; i++)
                usb_free_urb(acm->ru[i].urb);
        usb_free_urb(acm->ctrlurb);
 alloc_fail5:
@@ -1027,7 +1042,7 @@ static void acm_disconnect(struct usb_interface *intf)
 
        usb_kill_urb(acm->ctrlurb);
        usb_kill_urb(acm->writeurb);
-       for (i = 0; i < ACM_NRU; i++)
+       for (i = 0; i < acm->rx_buflimit; i++)
                usb_kill_urb(acm->ru[i].urb);
 
        INIT_LIST_HEAD(&acm->filled_read_bufs);
@@ -1039,7 +1054,7 @@ static void acm_disconnect(struct usb_interface *intf)
 
        acm_write_buffers_free(acm);
        usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
-       for (i = 0; i < ACM_NRB; i++)
+       for (i = 0; i < acm->rx_buflimit; i++)
                usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
 
        usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
@@ -1068,6 +1083,9 @@ static struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
        .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
        },
+       { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
+       .driver_info = SINGLE_RX_URB, /* firmware bug */
+       },
        /* control interfaces with various AT-command sets */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_ACM_PROTO_AT_V25TER) },
index fd2aaccdcbac7a4d04cc65f74743ea92541299fe..1bcaea32cfc19dc70550a70a8c365c4af2d29c38 100644 (file)
  * in line disciplines. They ask for empty space amount, receive our URB size,
  * and proceed to issue several 1-character writes, assuming they will fit.
  * The very first write takes a complete URB. Fortunately, this only happens
- * when processing onlcr, so we only need 2 buffers.
+ * when processing onlcr, so we only need 2 buffers. These values must be
+ * powers of 2.
  */
-#define ACM_NWB  2
-#define ACM_NRU  16
-#define ACM_NRB  16
+#define ACM_NW  2
+#define ACM_NR  16
 
 struct acm_wb {
        unsigned char *buf;
@@ -91,9 +91,10 @@ struct acm {
        struct urb *ctrlurb, *writeurb;                 /* urbs */
        u8 *ctrl_buffer;                                /* buffers of urbs */
        dma_addr_t ctrl_dma;                            /* dma handles of buffers */
-       struct acm_wb wb[ACM_NWB];
-       struct acm_ru ru[ACM_NRU];
-       struct acm_rb rb[ACM_NRB];
+       struct acm_wb wb[ACM_NW];
+       struct acm_ru ru[ACM_NR];
+       struct acm_rb rb[ACM_NR];
+       int rx_buflimit;
        int rx_endpoint;
        spinlock_t read_lock;
        struct list_head spare_read_urbs;
@@ -122,3 +123,4 @@ struct acm {
 
 /* constants describing various quirks and errors */
 #define NO_UNION_NORMAL                        1
+#define SINGLE_RX_URB                  2
index 28329ddf187c2f57cefee9e03395f1ee8912e707..ec510922af63a1fac195a022b1347ff4d2624c78 100644 (file)
@@ -3,7 +3,8 @@
 #
 
 usbcore-objs   := usb.o hub.o hcd.o urb.o message.o driver.o \
-                       config.o file.o buffer.o sysfs.o devio.o notify.o
+                       config.o file.o buffer.o sysfs.o endpoint.o \
+                       devio.o notify.o
 
 ifeq ($(CONFIG_PCI),y)
        usbcore-objs    += hcd-pci.o
index 545da37afca7bdec6f464d547d575f02570d10cc..3f8e06279c925e6a53db781902163138092dabeb 100644 (file)
@@ -515,19 +515,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 
 static struct usb_device *usbdev_lookup_minor(int minor)
 {
-       struct class_device *class_dev;
-       struct usb_device *dev = NULL;
+       struct device *device;
+       struct usb_device *udev = NULL;
 
        down(&usb_device_class->sem);
-       list_for_each_entry(class_dev, &usb_device_class->children, node) {
-               if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-                       dev = class_dev->class_data;
+       list_for_each_entry(device, &usb_device_class->devices, node) {
+               if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+                       udev = device->platform_data;
                        break;
                }
        }
        up(&usb_device_class->sem);
 
-       return dev;
+       return udev;
 };
 
 /*
@@ -823,8 +823,7 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)
 
 static int proc_resetdevice(struct dev_state *ps)
 {
-       return usb_reset_device(ps->dev);
-
+       return usb_reset_composite_device(ps->dev, NULL);
 }
 
 static int proc_setintf(struct dev_state *ps, void __user *arg)
@@ -923,8 +922,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
                                != USB_ENDPOINT_XFER_CONTROL)
                        return -EINVAL;
-               /* min 8 byte setup packet, max arbitrary */
-               if (uurb->buffer_length < 8 || uurb->buffer_length > PAGE_SIZE)
+               /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
+               if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
                        return -EINVAL;
                if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
                        return -ENOMEM;
@@ -982,7 +981,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        return -EFAULT;
                }
                for (totlen = u = 0; u < uurb->number_of_packets; u++) {
-                       if (isopkt[u].length > 1023) {
+                       /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */
+                       if (isopkt[u].length > 8192) {
                                kfree(isopkt);
                                return -EINVAL;
                        }
@@ -1078,7 +1078,9 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
        if (copy_from_user(&uurb, arg, sizeof(uurb)))
                return -EFAULT;
 
-       return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
+       return proc_do_submiturb(ps, &uurb,
+               (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc,
+               arg);
 }
 
 static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
@@ -1203,7 +1205,9 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
        if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
                return -EFAULT;
 
-       return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
+       return proc_do_submiturb(ps, &uurb,
+               (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc,
+               arg);
 }
 
 static int processcompl_compat(struct async *as, void __user * __user *arg)
@@ -1576,16 +1580,16 @@ static void usbdev_add(struct usb_device *dev)
 {
        int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
-       dev->class_dev = class_device_create(usb_device_class, NULL,
-                               MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+       dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+                               MKDEV(USB_DEVICE_MAJOR, minor),
                                "usbdev%d.%d", dev->bus->busnum, dev->devnum);
 
-       dev->class_dev->class_data = dev;
+       dev->usbfs_dev->platform_data = dev;
 }
 
 static void usbdev_remove(struct usb_device *dev)
 {
-       class_device_unregister(dev->class_dev);
+       device_unregister(dev->usbfs_dev);
 }
 
 static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
new file mode 100644 (file)
index 0000000..247b5a4
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * drivers/usb/core/endpoint.c
+ *
+ * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman
+ * (C) Copyright 2002,2004 IBM Corp.
+ * (C) Copyright 2006 Novell Inc.
+ *
+ * Endpoint sysfs stuff
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include "usb.h"
+
+/* endpoint stuff */
+
+struct ep_device {
+       struct usb_endpoint_descriptor *desc;
+       struct usb_device *udev;
+       struct device dev;
+};
+#define to_ep_device(_dev) \
+       container_of(_dev, struct ep_device, dev)
+
+struct ep_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct usb_device *,
+                       struct usb_endpoint_descriptor *, char *);
+};
+#define to_ep_attribute(_attr) \
+       container_of(_attr, struct ep_attribute, attr)
+
+#define usb_ep_attr(field, format_string)                      \
+static ssize_t show_ep_##field(struct device *dev,             \
+                              struct device_attribute *attr,   \
+                              char *buf)                       \
+{                                                              \
+       struct ep_device *ep = to_ep_device(dev);               \
+       return sprintf(buf, format_string, ep->desc->field);    \
+}                                                              \
+static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL);
+
+usb_ep_attr(bLength, "%02x\n")
+usb_ep_attr(bEndpointAddress, "%02x\n")
+usb_ep_attr(bmAttributes, "%02x\n")
+usb_ep_attr(bInterval, "%02x\n")
+
+static ssize_t show_ep_wMaxPacketSize(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct ep_device *ep = to_ep_device(dev);
+       return sprintf(buf, "%04x\n",
+                       le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff);
+}
+static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
+
+static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       struct ep_device *ep = to_ep_device(dev);
+       char *type = "unknown";
+
+       switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               type = "Control";
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               type = "Isoc";
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               type = "Bulk";
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               type = "Interrupt";
+               break;
+       }
+       return sprintf(buf, "%s\n", type);
+}
+static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL);
+
+static ssize_t show_ep_interval(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct ep_device *ep = to_ep_device(dev);
+       char unit;
+       unsigned interval = 0;
+       unsigned in;
+
+       in = (ep->desc->bEndpointAddress & USB_DIR_IN);
+
+       switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               if (ep->udev->speed == USB_SPEED_HIGH)  /* uframes per NAK */
+                       interval = ep->desc->bInterval;
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               interval = 1 << (ep->desc->bInterval - 1);
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
+                       interval = ep->desc->bInterval;
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               if (ep->udev->speed == USB_SPEED_HIGH)
+                       interval = 1 << (ep->desc->bInterval - 1);
+               else
+                       interval = ep->desc->bInterval;
+               break;
+       }
+       interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
+       if (interval % 1000)
+               unit = 'u';
+       else {
+               unit = 'm';
+               interval /= 1000;
+       }
+
+       return sprintf(buf, "%d%cs\n", interval, unit);
+}
+static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL);
+
+static ssize_t show_ep_direction(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct ep_device *ep = to_ep_device(dev);
+       char *direction;
+
+       if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                       USB_ENDPOINT_XFER_CONTROL)
+               direction = "both";
+       else if (ep->desc->bEndpointAddress & USB_DIR_IN)
+               direction = "in";
+       else
+               direction = "out";
+       return sprintf(buf, "%s\n", direction);
+}
+static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL);
+
+static struct attribute *ep_dev_attrs[] = {
+       &dev_attr_bLength.attr,
+       &dev_attr_bEndpointAddress.attr,
+       &dev_attr_bmAttributes.attr,
+       &dev_attr_bInterval.attr,
+       &dev_attr_wMaxPacketSize.attr,
+       &dev_attr_interval.attr,
+       &dev_attr_type.attr,
+       &dev_attr_direction.attr,
+       NULL,
+};
+static struct attribute_group ep_dev_attr_grp = {
+       .attrs = ep_dev_attrs,
+};
+
+static struct endpoint_class {
+       struct kref kref;
+       struct class *class;
+} *ep_class;
+
+static int init_endpoint_class(void)
+{
+       int result = 0;
+
+       if (ep_class != NULL) {
+               kref_get(&ep_class->kref);
+               goto exit;
+       }
+
+       ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL);
+       if (!ep_class) {
+               result = -ENOMEM;
+               goto exit;
+       }
+
+       kref_init(&ep_class->kref);
+       ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
+       if (IS_ERR(ep_class->class)) {
+               result = IS_ERR(ep_class->class);
+               kfree(ep_class);
+               ep_class = NULL;
+               goto exit;
+       }
+
+exit:
+       return result;
+}
+
+static void release_endpoint_class(struct kref *kref)
+{
+       /* Ok, we cheat as we know we only have one ep_class */
+       class_destroy(ep_class->class);
+       kfree(ep_class);
+       ep_class = NULL;
+}
+
+static void destroy_endpoint_class(void)
+{
+       if (ep_class)
+               kref_put(&ep_class->kref, release_endpoint_class);
+}
+
+static void ep_device_release(struct device *dev)
+{
+       struct ep_device *ep_dev = to_ep_device(dev);
+
+       dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
+       kfree(ep_dev);
+}
+
+void usb_create_ep_files(struct device *parent,
+                        struct usb_host_endpoint *endpoint,
+                        struct usb_device *udev)
+{
+       char name[8];
+       struct ep_device *ep_dev;
+       int minor;
+       int retval;
+
+       retval = init_endpoint_class();
+       if (retval)
+               goto exit;
+
+       ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
+       if (!ep_dev) {
+               retval = -ENOMEM;
+               goto exit;
+       }
+
+       /* fun calculation to determine the minor of this endpoint */
+       minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1);
+
+       ep_dev->desc = &endpoint->desc;
+       ep_dev->udev = udev;
+       ep_dev->dev.devt = MKDEV(442, minor);   // FIXME fake number...
+       ep_dev->dev.class = ep_class->class;
+       ep_dev->dev.parent = parent;
+       ep_dev->dev.release = ep_device_release;
+       snprintf(ep_dev->dev.bus_id, BUS_ID_SIZE, "usbdev%d.%d_ep%02x",
+                udev->bus->busnum, udev->devnum,
+                endpoint->desc.bEndpointAddress);
+
+       retval = device_register(&ep_dev->dev);
+       if (retval)
+               goto error;
+       sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
+
+       endpoint->ep_dev = ep_dev;
+
+       /* create the symlink to the old-style "ep_XX" directory */
+       sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
+       sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name);
+
+exit:
+       return;
+error:
+       kfree(ep_dev);
+       return;
+}
+
+void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
+{
+
+       if (endpoint->ep_dev) {
+               char name[8];
+
+               sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
+               sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name);
+               sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp);
+               device_unregister(&endpoint->ep_dev->dev);
+               endpoint->ep_dev = NULL;
+       }
+       destroy_endpoint_class();
+}
+
+
index b263a54a13c0b79099bf0989fa818b862284521a..f65b193cde3d43ab1a68fdd31575b298990f18cc 100644 (file)
@@ -61,33 +61,66 @@ static struct file_operations usb_fops = {
        .open =         usb_open,
 };
 
-static struct class *usb_class;
+static struct usb_class {
+       struct kref kref;
+       struct class *class;
+} *usb_class;
 
-int usb_major_init(void)
+static int init_usb_class(void)
 {
-       int error;
+       int result = 0;
 
-       error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
-       if (error) {
-               err("unable to get major %d for usb devices", USB_MAJOR);
-               goto out;
+       if (usb_class != NULL) {
+               kref_get(&usb_class->kref);
+               goto exit;
+       }
+
+       usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL);
+       if (!usb_class) {
+               result = -ENOMEM;
+               goto exit;
        }
 
-       usb_class = class_create(THIS_MODULE, "usb");
-       if (IS_ERR(usb_class)) {
-               error = PTR_ERR(usb_class);
+       kref_init(&usb_class->kref);
+       usb_class->class = class_create(THIS_MODULE, "usb");
+       if (IS_ERR(usb_class->class)) {
+               result = IS_ERR(usb_class->class);
                err("class_create failed for usb devices");
-               unregister_chrdev(USB_MAJOR, "usb");
-               goto out;
+               kfree(usb_class);
+               usb_class = NULL;
        }
 
-out:
+exit:
+       return result;
+}
+
+static void release_usb_class(struct kref *kref)
+{
+       /* Ok, we cheat as we know we only have one usb_class */
+       class_destroy(usb_class->class);
+       kfree(usb_class);
+       usb_class = NULL;
+}
+
+static void destroy_usb_class(void)
+{
+       if (usb_class)
+               kref_put(&usb_class->kref, release_usb_class);
+}
+
+int usb_major_init(void)
+{
+       int error;
+
+       error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
+       if (error)
+               err("unable to get major %d for usb devices", USB_MAJOR);
+
        return error;
 }
 
 void usb_major_cleanup(void)
 {
-       class_destroy(usb_class);
        unregister_chrdev(USB_MAJOR, "usb");
 }
 
@@ -146,6 +179,10 @@ int usb_register_dev(struct usb_interface *intf,
        }
        spin_unlock (&minor_lock);
 
+       if (retval)
+               goto exit;
+
+       retval = init_usb_class();
        if (retval)
                goto exit;
 
@@ -158,14 +195,13 @@ int usb_register_dev(struct usb_interface *intf,
                ++temp;
        else
                temp = name;
-       intf->class_dev = class_device_create(usb_class, NULL,
-                                             MKDEV(USB_MAJOR, minor),
-                                             &intf->dev, "%s", temp);
-       if (IS_ERR(intf->class_dev)) {
+       intf->usb_dev = device_create(usb_class->class, &intf->dev,
+                                     MKDEV(USB_MAJOR, minor), "%s", temp);
+       if (IS_ERR(intf->usb_dev)) {
                spin_lock (&minor_lock);
                usb_minors[intf->minor] = NULL;
                spin_unlock (&minor_lock);
-               retval = PTR_ERR(intf->class_dev);
+               retval = PTR_ERR(intf->usb_dev);
        }
 exit:
        return retval;
@@ -206,9 +242,10 @@ void usb_deregister_dev(struct usb_interface *intf,
        spin_unlock (&minor_lock);
 
        snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
-       class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor));
-       intf->class_dev = NULL;
+       device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+       intf->usb_dev = NULL;
        intf->minor = -1;
+       destroy_usb_class();
 }
 EXPORT_SYMBOL(usb_deregister_dev);
 
index 90b8d43c6b339eb233045dc8d550176ea67192f6..e1731ff8af4d803f73489200527ca45caf8468df 100644 (file)
@@ -432,15 +432,22 @@ static void hub_power_on(struct usb_hub *hub)
 {
        int port1;
        unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
-       u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
-
-       /* if hub supports power switching, enable power on each port */
-       if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
+       u16 wHubCharacteristics =
+                       le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+       /* Enable power on each port.  Some hubs have reserved values
+        * of LPSM (> 2) in their descriptors, even though they are
+        * USB 2.0 hubs.  Some hubs do not implement port-power switching
+        * but only emulate it.  In all cases, the ports won't work
+        * unless we send these messages to the hub.
+        */
+       if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2)
                dev_dbg(hub->intfdev, "enabling power on all ports\n");
-               for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
-                       set_port_feature(hub->hdev, port1,
-                                       USB_PORT_FEAT_POWER);
-       }
+       else
+               dev_dbg(hub->intfdev, "trying to enable port power on "
+                               "non-switchable hub\n");
+       for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
+               set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
 
        /* Wait at least 100 msec for power to become stable */
        msleep(max(pgood_delay, (unsigned) 100));
@@ -518,15 +525,16 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
 
 
 /* caller has locked the hub device */
-static void hub_pre_reset(struct usb_hub *hub, int disable_ports)
+static void hub_pre_reset(struct usb_interface *intf)
 {
+       struct usb_hub *hub = usb_get_intfdata(intf);
        struct usb_device *hdev = hub->hdev;
        int port1;
 
        for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
                if (hdev->children[port1 - 1]) {
                        usb_disconnect(&hdev->children[port1 - 1]);
-                       if (disable_ports)
+                       if (hub->error == 0)
                                hub_port_disable(hub, port1, 0);
                }
        }
@@ -534,8 +542,10 @@ static void hub_pre_reset(struct usb_hub *hub, int disable_ports)
 }
 
 /* caller has locked the hub device */
-static void hub_post_reset(struct usb_hub *hub)
+static void hub_post_reset(struct usb_interface *intf)
 {
+       struct usb_hub *hub = usb_get_intfdata(intf);
+
        hub_activate(hub);
        hub_power_on(hub);
 }
@@ -795,15 +805,16 @@ static void hub_disconnect(struct usb_interface *intf)
        struct usb_hub *hub = usb_get_intfdata (intf);
        struct usb_device *hdev;
 
+       /* Disconnect all children and quiesce the hub */
+       hub->error = 0;
+       hub_pre_reset(intf);
+
        usb_set_intfdata (intf, NULL);
        hdev = hub->hdev;
 
        if (hdev->speed == USB_SPEED_HIGH)
                highspeed_hubs--;
 
-       /* Disconnect all children and quiesce the hub */
-       hub_pre_reset(hub, 1);
-
        usb_free_urb(hub->urb);
        hub->urb = NULL;
 
@@ -1169,6 +1180,7 @@ static int choose_configuration(struct usb_device *udev)
 {
        int i;
        int num_configs;
+       int insufficient_power = 0;
        struct usb_host_config *c, *best;
 
        best = NULL;
@@ -1221,8 +1233,10 @@ static int choose_configuration(struct usb_device *udev)
                 */
 
                /* Rule out configs that draw too much bus current */
-               if (c->desc.bMaxPower * 2 > udev->bus_mA)
+               if (c->desc.bMaxPower * 2 > udev->bus_mA) {
+                       insufficient_power++;
                        continue;
+               }
 
                /* If the first config's first interface is COMM/2/0xff
                 * (MSFT RNDIS), rule it out unless Linux has host-side
@@ -1231,7 +1245,7 @@ static int choose_configuration(struct usb_device *udev)
                                && desc->bInterfaceClass == USB_CLASS_COMM
                                && desc->bInterfaceSubClass == 2
                                && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS
+#ifndef CONFIG_USB_NET_RNDIS_HOST
                        continue;
 #else
                        best = c;
@@ -1256,6 +1270,11 @@ static int choose_configuration(struct usb_device *udev)
                        best = c;
        }
 
+       if (insufficient_power > 0)
+               dev_info(&udev->dev, "rejected %d configuration%s "
+                       "due to insufficient available bus power\n",
+                       insufficient_power, plural(insufficient_power));
+
        if (best) {
                i = best->desc.bConfigurationValue;
                dev_info(&udev->dev,
@@ -2732,7 +2751,8 @@ static void hub_events(void)
 
                /* If the hub has died, clean up after it */
                if (hdev->state == USB_STATE_NOTATTACHED) {
-                       hub_pre_reset(hub, 0);
+                       hub->error = -ENODEV;
+                       hub_pre_reset(intf);
                        goto loop;
                }
 
@@ -2744,7 +2764,7 @@ static void hub_events(void)
                        dev_dbg (hub_dev, "resetting for error %d\n",
                                hub->error);
 
-                       ret = usb_reset_device(hdev);
+                       ret = usb_reset_composite_device(hdev, intf);
                        if (ret) {
                                dev_dbg (hub_dev,
                                        "error resetting hub: %d\n", ret);
@@ -2913,6 +2933,8 @@ static struct usb_driver hub_driver = {
        .disconnect =   hub_disconnect,
        .suspend =      hub_suspend,
        .resume =       hub_resume,
+       .pre_reset =    hub_pre_reset,
+       .post_reset =   hub_post_reset,
        .ioctl =        hub_ioctl,
        .id_table =     hub_id_table,
 };
@@ -2992,9 +3014,9 @@ static int config_descriptors_changed(struct usb_device *udev)
  * usb_reset_device - perform a USB port reset to reinitialize a device
  * @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
  *
- * WARNING - don't reset any device unless drivers for all of its
- * interfaces are expecting that reset!  Maybe some driver->reset()
- * method should eventually help ensure sufficient cooperation.
+ * WARNING - don't use this routine to reset a composite device
+ * (one with multiple interfaces owned by separate drivers)!
+ * Use usb_reset_composite_device() instead.
  *
  * Do a port reset, reassign the device's address, and establish its
  * former operating configuration.  If the reset fails, or the device's
@@ -3018,7 +3040,6 @@ int usb_reset_device(struct usb_device *udev)
        struct usb_device               *parent_hdev = udev->parent;
        struct usb_hub                  *parent_hub;
        struct usb_device_descriptor    descriptor = udev->descriptor;
-       struct usb_hub                  *hub = NULL;
        int                             i, ret = 0;
        int                             port1 = udev->portnum;
 
@@ -3036,14 +3057,6 @@ int usb_reset_device(struct usb_device *udev)
        }
        parent_hub = hdev_to_hub(parent_hdev);
 
-       /* If we're resetting an active hub, take some special actions */
-       if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 &&
-                       udev->actconfig->interface[0]->dev.driver ==
-                               &hub_driver.driver &&
-                       (hub = hdev_to_hub(udev)) != NULL) {
-               hub_pre_reset(hub, 0);
-       }
-
        set_bit(port1, parent_hub->busy_bits);
        for (i = 0; i < SET_CONFIG_TRIES; ++i) {
 
@@ -3102,11 +3115,87 @@ int usb_reset_device(struct usb_device *udev)
        }
 
 done:
-       if (hub)
-               hub_post_reset(hub);
        return 0;
  
 re_enumerate:
        hub_port_logical_disconnect(parent_hub, port1);
        return -ENODEV;
 }
+
+/**
+ * usb_reset_composite_device - warn interface drivers and perform a USB port reset
+ * @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
+ * @iface: interface bound to the driver making the request (optional)
+ *
+ * Warns all drivers bound to registered interfaces (using their pre_reset
+ * method), performs the port reset, and then lets the drivers know that
+ * the reset is over (using their post_reset method).
+ *
+ * Return value is the same as for usb_reset_device().
+ *
+ * The caller must own the device lock.  For example, it's safe to use
+ * this from a driver probe() routine after downloading new firmware.
+ * For calls that might not occur during probe(), drivers should lock
+ * the device using usb_lock_device_for_reset().
+ *
+ * The interface locks are acquired during the pre_reset stage and released
+ * during the post_reset stage.  However if iface is not NULL and is
+ * currently being probed, we assume that the caller already owns its
+ * lock.
+ */
+int usb_reset_composite_device(struct usb_device *udev,
+               struct usb_interface *iface)
+{
+       int ret;
+       struct usb_host_config *config = udev->actconfig;
+
+       if (udev->state == USB_STATE_NOTATTACHED ||
+                       udev->state == USB_STATE_SUSPENDED) {
+               dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
+                               udev->state);
+               return -EINVAL;
+       }
+
+       if (iface && iface->condition != USB_INTERFACE_BINDING)
+               iface = NULL;
+
+       if (config) {
+               int i;
+               struct usb_interface *cintf;
+               struct usb_driver *drv;
+
+               for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+                       cintf = config->interface[i];
+                       if (cintf != iface)
+                               down(&cintf->dev.sem);
+                       if (device_is_registered(&cintf->dev) &&
+                                       cintf->dev.driver) {
+                               drv = to_usb_driver(cintf->dev.driver);
+                               if (drv->pre_reset)
+                                       (drv->pre_reset)(cintf);
+                       }
+               }
+       }
+
+       ret = usb_reset_device(udev);
+
+       if (config) {
+               int i;
+               struct usb_interface *cintf;
+               struct usb_driver *drv;
+
+               for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
+                       cintf = config->interface[i];
+                       if (device_is_registered(&cintf->dev) &&
+                                       cintf->dev.driver) {
+                               drv = to_usb_driver(cintf->dev.driver);
+                               if (drv->post_reset)
+                                       (drv->post_reset)(cintf);
+                       }
+                       if (cintf != iface)
+                               up(&cintf->dev.sem);
+               }
+       }
+
+       return ret;
+}
index 08fb20f06f3e9864971dee4243e4ed7b5fba4eae..8569600f313071dbda5fb278c2cd06d77d3c7862 100644 (file)
@@ -157,6 +157,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
 }
 
 
+/**
+ * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion
+ * @usb_dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @data: pointer to the data to send
+ * @len: length in bytes of the data to send
+ * @actual_length: pointer to a location to put the actual length transferred in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ *     timing out (if 0 the wait is forever)
+ * Context: !in_interrupt ()
+ *
+ * This function sends a simple interrupt message to a specified endpoint and
+ * waits for the message to complete, or timeout.
+ *
+ * If successful, it returns 0, otherwise a negative error number.  The number
+ * of actual bytes transferred will be stored in the actual_length paramater.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler.  If you need an asynchronous message, or need to send a message
+ * from within interrupt context, use usb_submit_urb() If a thread in your
+ * driver uses this call, make sure your disconnect() method can wait for it to
+ * complete.  Since you don't have a handle on the URB used, you can't cancel
+ * the request.
+ */
+int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
+                     void *data, int len, int *actual_length, int timeout)
+{
+       return usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout);
+}
+EXPORT_SYMBOL_GPL(usb_interrupt_msg);
+
 /**
  *     usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
  *     @usb_dev: pointer to the usb device to send the message to
@@ -1380,15 +1411,7 @@ free_interfaces:
                                return ret;
                        }
                }
-       }
-
-       /* if it's already configured, clear out old state first.
-        * getting rid of old interfaces means unbinding their drivers.
-        */
-       if (dev->state != USB_STATE_ADDRESS)
-               usb_disable_device (dev, 1);    // Skip ep0
 
-       if (cp) {
                i = dev->bus_mA - cp->desc.bMaxPower * 2;
                if (i < 0)
                        dev_warn(&dev->dev, "new config #%d exceeds power "
@@ -1396,84 +1419,91 @@ free_interfaces:
                                        configuration, -i);
        }
 
+       /* if it's already configured, clear out old state first.
+        * getting rid of old interfaces means unbinding their drivers.
+        */
+       if (dev->state != USB_STATE_ADDRESS)
+               usb_disable_device (dev, 1);    // Skip ep0
+
        if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                        USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0)
-               goto free_interfaces;
+                       NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
+
+               /* All the old state is gone, so what else can we do?
+                * The device is probably useless now anyway.
+                */
+               cp = NULL;
+       }
 
        dev->actconfig = cp;
-       if (!cp)
+       if (!cp) {
                usb_set_device_state(dev, USB_STATE_ADDRESS);
-       else {
-               usb_set_device_state(dev, USB_STATE_CONFIGURED);
+               goto free_interfaces;
+       }
+       usb_set_device_state(dev, USB_STATE_CONFIGURED);
 
-               /* Initialize the new interface structures and the
-                * hc/hcd/usbcore interface/endpoint state.
-                */
-               for (i = 0; i < nintf; ++i) {
-                       struct usb_interface_cache *intfc;
-                       struct usb_interface *intf;
-                       struct usb_host_interface *alt;
-
-                       cp->interface[i] = intf = new_interfaces[i];
-                       intfc = cp->intf_cache[i];
-                       intf->altsetting = intfc->altsetting;
-                       intf->num_altsetting = intfc->num_altsetting;
-                       kref_get(&intfc->ref);
-
-                       alt = usb_altnum_to_altsetting(intf, 0);
-
-                       /* No altsetting 0?  We'll assume the first altsetting.
-                        * We could use a GetInterface call, but if a device is
-                        * so non-compliant that it doesn't have altsetting 0
-                        * then I wouldn't trust its reply anyway.
-                        */
-                       if (!alt)
-                               alt = &intf->altsetting[0];
-
-                       intf->cur_altsetting = alt;
-                       usb_enable_interface(dev, intf);
-                       intf->dev.parent = &dev->dev;
-                       intf->dev.driver = NULL;
-                       intf->dev.bus = &usb_bus_type;
-                       intf->dev.dma_mask = dev->dev.dma_mask;
-                       intf->dev.release = release_interface;
-                       device_initialize (&intf->dev);
-                       mark_quiesced(intf);
-                       sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
-                                dev->bus->busnum, dev->devpath,
-                                configuration,
-                                alt->desc.bInterfaceNumber);
-               }
-               kfree(new_interfaces);
+       /* Initialize the new interface structures and the
+        * hc/hcd/usbcore interface/endpoint state.
+        */
+       for (i = 0; i < nintf; ++i) {
+               struct usb_interface_cache *intfc;
+               struct usb_interface *intf;
+               struct usb_host_interface *alt;
+
+               cp->interface[i] = intf = new_interfaces[i];
+               intfc = cp->intf_cache[i];
+               intf->altsetting = intfc->altsetting;
+               intf->num_altsetting = intfc->num_altsetting;
+               kref_get(&intfc->ref);
 
-               if (cp->string == NULL)
-                       cp->string = usb_cache_string(dev,
-                                       cp->desc.iConfiguration);
+               alt = usb_altnum_to_altsetting(intf, 0);
 
-               /* Now that all the interfaces are set up, register them
-                * to trigger binding of drivers to interfaces.  probe()
-                * routines may install different altsettings and may
-                * claim() any interfaces not yet bound.  Many class drivers
-                * need that: CDC, audio, video, etc.
+               /* No altsetting 0?  We'll assume the first altsetting.
+                * We could use a GetInterface call, but if a device is
+                * so non-compliant that it doesn't have altsetting 0
+                * then I wouldn't trust its reply anyway.
                 */
-               for (i = 0; i < nintf; ++i) {
-                       struct usb_interface *intf = cp->interface[i];
-
-                       dev_dbg (&dev->dev,
-                               "adding %s (config #%d, interface %d)\n",
-                               intf->dev.bus_id, configuration,
-                               intf->cur_altsetting->desc.bInterfaceNumber);
-                       ret = device_add (&intf->dev);
-                       if (ret != 0) {
-                               dev_err(&dev->dev,
-                                       "device_add(%s) --> %d\n",
-                                       intf->dev.bus_id,
-                                       ret);
-                               continue;
-                       }
-                       usb_create_sysfs_intf_files (intf);
+               if (!alt)
+                       alt = &intf->altsetting[0];
+
+               intf->cur_altsetting = alt;
+               usb_enable_interface(dev, intf);
+               intf->dev.parent = &dev->dev;
+               intf->dev.driver = NULL;
+               intf->dev.bus = &usb_bus_type;
+               intf->dev.dma_mask = dev->dev.dma_mask;
+               intf->dev.release = release_interface;
+               device_initialize (&intf->dev);
+               mark_quiesced(intf);
+               sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
+                        dev->bus->busnum, dev->devpath,
+                        configuration, alt->desc.bInterfaceNumber);
+       }
+       kfree(new_interfaces);
+
+       if (cp->string == NULL)
+               cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
+
+       /* Now that all the interfaces are set up, register them
+        * to trigger binding of drivers to interfaces.  probe()
+        * routines may install different altsettings and may
+        * claim() any interfaces not yet bound.  Many class drivers
+        * need that: CDC, audio, video, etc.
+        */
+       for (i = 0; i < nintf; ++i) {
+               struct usb_interface *intf = cp->interface[i];
+
+               dev_dbg (&dev->dev,
+                       "adding %s (config #%d, interface %d)\n",
+                       intf->dev.bus_id, configuration,
+                       intf->cur_altsetting->desc.bInterfaceNumber);
+               ret = device_add (&intf->dev);
+               if (ret != 0) {
+                       dev_err(&dev->dev, "device_add(%s) --> %d\n",
+                               intf->dev.bus_id, ret);
+                       continue;
                }
+               usb_create_sysfs_intf_files (intf);
        }
 
        return 0;
index 71d881327e88e0aa05611a7acd3967ec1b24b4c4..3f49bf51cff75a6f4de11b7b2cd73bffbb52a931 100644 (file)
 #include <linux/usb.h>
 #include "usb.h"
 
-/* endpoint stuff */
-struct ep_object {
-       struct usb_endpoint_descriptor *desc;
-       struct usb_device *udev;
-       struct kobject kobj;
-};
-#define to_ep_object(_kobj) \
-       container_of(_kobj, struct ep_object, kobj)
-
-struct ep_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct usb_device *,
-                       struct usb_endpoint_descriptor *, char *);
-};
-#define to_ep_attribute(_attr) \
-       container_of(_attr, struct ep_attribute, attr)
-
-#define EP_ATTR(_name)                                         \
-struct ep_attribute ep_##_name = {                             \
-       .attr = {.name = #_name, .owner = THIS_MODULE,          \
-                       .mode = S_IRUGO},                       \
-       .show = show_ep_##_name}
-
-#define usb_ep_attr(field, format_string)                      \
-static ssize_t show_ep_##field(struct usb_device *udev,                \
-               struct usb_endpoint_descriptor *desc,           \
-               char *buf)                                      \
-{                                                              \
-       return sprintf(buf, format_string, desc->field);        \
-}                                                              \
-static EP_ATTR(field);
-
-usb_ep_attr(bLength, "%02x\n")
-usb_ep_attr(bEndpointAddress, "%02x\n")
-usb_ep_attr(bmAttributes, "%02x\n")
-usb_ep_attr(bInterval, "%02x\n")
-
-static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev,
-               struct usb_endpoint_descriptor *desc, char *buf)
-{
-       return sprintf(buf, "%04x\n",
-                       le16_to_cpu(desc->wMaxPacketSize) & 0x07ff);
-}
-static EP_ATTR(wMaxPacketSize);
-
-static ssize_t show_ep_type(struct usb_device *udev,
-               struct usb_endpoint_descriptor *desc, char *buf)
-{
-       char *type = "unknown";
-
-       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               type = "Control";
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               type = "Isoc";
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               type = "Bulk";
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               type = "Interrupt";
-               break;
-       }
-       return sprintf(buf, "%s\n", type);
-}
-static EP_ATTR(type);
-
-static ssize_t show_ep_interval(struct usb_device *udev,
-               struct usb_endpoint_descriptor *desc, char *buf)
-{
-       char unit;
-       unsigned interval = 0;
-       unsigned in;
-
-       in = (desc->bEndpointAddress & USB_DIR_IN);
-
-       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               if (udev->speed == USB_SPEED_HIGH)      /* uframes per NAK */
-                       interval = desc->bInterval;
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               interval = 1 << (desc->bInterval - 1);
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
-                       interval = desc->bInterval;
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               if (udev->speed == USB_SPEED_HIGH)
-                       interval = 1 << (desc->bInterval - 1);
-               else
-                       interval = desc->bInterval;
-               break;
-       }
-       interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
-       if (interval % 1000)
-               unit = 'u';
-       else {
-               unit = 'm';
-               interval /= 1000;
-       }
-
-       return sprintf(buf, "%d%cs\n", interval, unit);
-}
-static EP_ATTR(interval);
-
-static ssize_t show_ep_direction(struct usb_device *udev,
-               struct usb_endpoint_descriptor *desc, char *buf)
-{
-       char *direction;
-
-       if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-                       USB_ENDPOINT_XFER_CONTROL)
-               direction = "both";
-       else if (desc->bEndpointAddress & USB_DIR_IN)
-               direction = "in";
-       else
-               direction = "out";
-       return sprintf(buf, "%s\n", direction);
-}
-static EP_ATTR(direction);
-
-static struct attribute *ep_attrs[] = {
-       &ep_bLength.attr,
-       &ep_bEndpointAddress.attr,
-       &ep_bmAttributes.attr,
-       &ep_bInterval.attr,
-       &ep_wMaxPacketSize.attr,
-       &ep_type.attr,
-       &ep_interval.attr,
-       &ep_direction.attr,
-       NULL,
-};
-
-static void ep_object_release(struct kobject *kobj)
-{
-       kfree(to_ep_object(kobj));
-}
-
-static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr,
-               char *buf)
-{
-       struct ep_object *ep_obj = to_ep_object(kobj);
-       struct ep_attribute *ep_attr = to_ep_attribute(attr);
-
-       return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf);
-}
-
-static struct sysfs_ops ep_object_sysfs_ops = {
-       .show =                 ep_object_show,
-};
-
-static struct kobj_type ep_object_ktype = {
-       .release =              ep_object_release,
-       .sysfs_ops =            &ep_object_sysfs_ops,
-       .default_attrs =        ep_attrs,
-};
-
-static void usb_create_ep_files(struct kobject *parent,
-               struct usb_host_endpoint *endpoint,
-               struct usb_device *udev)
-{
-       struct ep_object *ep_obj;
-       struct kobject *kobj;
-
-       ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL);
-       if (!ep_obj)
-               return;
-
-       ep_obj->desc = &endpoint->desc;
-       ep_obj->udev = udev;
-
-       kobj = &ep_obj->kobj;
-       kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress);
-       kobj->parent = parent;
-       kobj->ktype = &ep_object_ktype;
-
-       /* Don't use kobject_register, because it generates a hotplug event */
-       kobject_init(kobj);
-       if (kobject_add(kobj) == 0)
-               endpoint->kobj = kobj;
-       else
-               kobject_put(kobj);
-}
-
-static void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
-{
-
-       if (endpoint->kobj) {
-               kobject_del(endpoint->kobj);
-               kobject_put(endpoint->kobj);
-               endpoint->kobj = NULL;
-       }
-}
-
 /* Active configuration fields */
 #define usb_actconfig_show(field, multiplier, format_string)           \
 static ssize_t  show_##field (struct device *dev,                      \
@@ -420,7 +223,7 @@ void usb_create_sysfs_dev_files (struct usb_device *udev)
        if (udev->serial)
                device_create_file (dev, &dev_attr_serial);
        device_create_file (dev, &dev_attr_configuration);
-       usb_create_ep_files(&dev->kobj, &udev->ep0, udev);
+       usb_create_ep_files(dev, &udev->ep0, udev);
 }
 
 void usb_remove_sysfs_dev_files (struct usb_device *udev)
@@ -524,7 +327,7 @@ static inline void usb_create_intf_ep_files(struct usb_interface *intf,
 
        iface_desc = intf->cur_altsetting;
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
-               usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i],
+               usb_create_ep_files(&intf->dev, &iface_desc->endpoint[i],
                                udev);
 }
 
index b7fdc1cd134a55a7e04636c0e174eb4465892a08..515310751303752d37390357d8bc9592e20e2592 100644 (file)
@@ -1207,6 +1207,7 @@ EXPORT_SYMBOL(usb_ifnum_to_if);
 EXPORT_SYMBOL(usb_altnum_to_altsetting);
 
 EXPORT_SYMBOL(usb_reset_device);
+EXPORT_SYMBOL(usb_reset_composite_device);
 
 EXPORT_SYMBOL(__usb_get_extra_descriptor);
 
index 4647e1ebc68d08fcfadae61bd9e0f4310c23abc0..7a650c763a627a2992f0133f662f104fba94f572 100644 (file)
@@ -4,6 +4,9 @@ extern void usb_create_sysfs_dev_files (struct usb_device *dev);
 extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
 extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
 extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
+extern void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
+                               struct usb_device *udev);
+extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
index 9c4422ac9de41d25db79c6dfd7c5ddb59ae917aa..078daa026718b234c3994d81a4c6f57a6c27557f 100644 (file)
@@ -49,7 +49,7 @@
 #include <asm/unaligned.h>
 
 #include <linux/usb_ch9.h>
-#include <linux/usb_cdc.h>
+#include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
 #include <linux/random.h>
@@ -101,9 +101,9 @@ static const char driver_desc [] = DRIVER_DESC;
 
 /* CDC and RNDIS support the same host-chosen outgoing packet filters. */
 #define        DEFAULT_FILTER  (USB_CDC_PACKET_TYPE_BROADCAST \
-                       |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
-                       |USB_CDC_PACKET_TYPE_PROMISCUOUS \
-                       |USB_CDC_PACKET_TYPE_DIRECTED)
+                       |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+                       |USB_CDC_PACKET_TYPE_PROMISCUOUS \
+                       |USB_CDC_PACKET_TYPE_DIRECTED)
 
 
 /*-------------------------------------------------------------------------*/
@@ -318,7 +318,7 @@ static inline int rndis_active(struct eth_dev *dev)
 #define DEFAULT_QLEN   2       /* double buffering by default */
 
 /* peak bulk transfer bits-per-second */
-#define        HS_BPS          (13 * 512 * 8 * 1000 * 8)
+#define        HS_BPS          (13 * 512 * 8 * 1000 * 8)
 #define        FS_BPS          (19 *  64 * 1 * 1000 * 8)
 
 #ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -466,7 +466,7 @@ eth_config = {
 };
 
 #ifdef CONFIG_USB_ETH_RNDIS
-static struct usb_config_descriptor 
+static struct usb_config_descriptor
 rndis_config = {
        .bLength =              sizeof rndis_config,
        .bDescriptorType =      USB_DT_CONFIG,
@@ -511,7 +511,7 @@ static const struct usb_interface_descriptor
 rndis_control_intf = {
        .bLength =              sizeof rndis_control_intf,
        .bDescriptorType =      USB_DT_INTERFACE,
-         
+
        .bInterfaceNumber =     0,
        .bNumEndpoints =        1,
        .bInterfaceClass =      USB_CLASS_COMM,
@@ -545,20 +545,20 @@ static const struct usb_cdc_union_desc union_desc = {
 #ifdef CONFIG_USB_ETH_RNDIS
 
 static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
-       .bLength =              sizeof call_mgmt_descriptor,
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+       .bLength =              sizeof call_mgmt_descriptor,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
 
-       .bmCapabilities =       0x00,
-       .bDataInterface =       0x01,
+       .bmCapabilities =       0x00,
+       .bDataInterface =       0x01,
 };
 
 static const struct usb_cdc_acm_descriptor acm_descriptor = {
-       .bLength =              sizeof acm_descriptor,
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+       .bLength =              sizeof acm_descriptor,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
 
-       .bmCapabilities =       0x00,
+       .bmCapabilities =       0x00,
 };
 
 #endif
@@ -595,7 +595,7 @@ static const struct usb_cdc_ether_desc ether_desc = {
  * RNDIS requires the status endpoint, since it uses that encapsulation
  * mechanism for its funky RPC scheme.
  */
+
 #define LOG2_STATUS_INTERVAL_MSEC      5       /* 1 << 5 == 32 msec */
 #define STATUS_BYTECOUNT               16      /* 8 byte header + data */
 
@@ -978,7 +978,7 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
 
                result = usb_ep_enable (dev->status_ep, dev->status);
                if (result != 0) {
-                       DEBUG (dev, "enable %s --> %d\n", 
+                       DEBUG (dev, "enable %s --> %d\n",
                                dev->status_ep->name, result);
                        goto done;
                }
@@ -1002,15 +1002,15 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
        if (!cdc_active(dev)) {
                result = usb_ep_enable (dev->in_ep, dev->in);
                if (result != 0) {
-                       DEBUG(dev, "enable %s --> %d\n", 
+                       DEBUG(dev, "enable %s --> %d\n",
                                dev->in_ep->name, result);
                        goto done;
                }
 
                result = usb_ep_enable (dev->out_ep, dev->out);
                if (result != 0) {
-                       DEBUG (dev, "enable %s --> %d\n", 
-                               dev->in_ep->name, result);
+                       DEBUG (dev, "enable %s --> %d\n",
+                               dev->out_ep->name, result);
                        goto done;
                }
        }
@@ -1144,7 +1144,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
 #ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_SPEED_HIGH:    speed = "high"; break;
 #endif
-               default:                speed = "?"; break;
+               default:                speed = "?"; break;
                }
 
                dev->config = number;
@@ -1206,7 +1206,7 @@ static void issue_start_status (struct eth_dev *dev)
        struct usb_request              *req = dev->stat_req;
        struct usb_cdc_notification     *event;
        int                             value;
+
        DEBUG (dev, "%s, flush old status first\n", __FUNCTION__);
 
        /* flush old status
@@ -1268,7 +1268,7 @@ static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req)
 {
        struct eth_dev          *dev = ep->driver_data;
        int                     status;
-       
+
        /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
        spin_lock(&dev->lock);
        status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf);
@@ -1472,7 +1472,7 @@ done_set_intf:
 
 #endif /* DEV_CONFIG_CDC */
 
-#ifdef CONFIG_USB_ETH_RNDIS            
+#ifdef CONFIG_USB_ETH_RNDIS
        /* RNDIS uses the CDC command encapsulation mechanism to implement
         * an RPC scheme, with much getting/setting of attributes by OID.
         */
@@ -1489,7 +1489,7 @@ done_set_intf:
                req->complete = rndis_command_complete;
                /* later, rndis_control_ack () sends a notification */
                break;
-               
+
        case USB_CDC_GET_ENCAPSULATED_RESPONSE:
                if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
                                        == ctrl->bRequestType
@@ -1641,7 +1641,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
                DEBUG (dev, "no rx skb\n");
                goto enomem;
        }
-       
+
        /* Some platforms perform better when IP packets are aligned,
         * but on at least one, checksumming fails otherwise.  Note:
         * RNDIS headers involve variable numbers of LE32 values.
@@ -1720,7 +1720,7 @@ quiesce:
        case -EOVERFLOW:
                dev->stats.rx_over_errors++;
                // FALLTHROUGH
-           
+
        default:
                dev->stats.rx_errors++;
                DEBUG (dev, "rx status %d\n", status);
@@ -1915,7 +1915,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
                                sizeof (struct rndis_packet_msg_type));
                if (!skb_rndis)
                        goto drop;
-       
+
                dev_kfree_skb_any (skb);
                skb = skb_rndis;
                rndis_add_hdr (skb);
@@ -2001,7 +2001,7 @@ static int rndis_control_ack (struct net_device *net)
        struct eth_dev          *dev = netdev_priv(net);
        u32                     length;
        struct usb_request      *resp = dev->stat_req;
-       
+
        /* in case RNDIS calls this after disconnect */
        if (!dev->status) {
                DEBUG (dev, "status ENODEV\n");
@@ -2021,16 +2021,16 @@ static int rndis_control_ack (struct net_device *net)
        resp->length = 8;
        resp->complete = rndis_control_ack_complete;
        resp->context = dev;
-       
+
        *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
        *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
-       
+
        length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC);
        if (length < 0) {
                resp->status = 0;
                rndis_control_ack_complete (dev->status_ep, resp);
        }
-       
+
        return 0;
 }
 
@@ -2047,7 +2047,7 @@ static void eth_start (struct eth_dev *dev, gfp_t gfp_flags)
        /* fill the rx queue */
        rx_fill (dev, gfp_flags);
 
-       /* and open the tx floodgates */ 
+       /* and open the tx floodgates */
        atomic_set (&dev->tx_qlen, 0);
        netif_wake_queue (dev->net);
        if (rndis_active(dev)) {
@@ -2076,7 +2076,7 @@ static int eth_stop (struct net_device *net)
        netif_stop_queue (net);
 
        DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
-               dev->stats.rx_packets, dev->stats.tx_packets, 
+               dev->stats.rx_packets, dev->stats.tx_packets,
                dev->stats.rx_errors, dev->stats.tx_errors
                );
 
@@ -2095,7 +2095,7 @@ static int eth_stop (struct net_device *net)
                        usb_ep_enable (dev->status_ep, dev->status);
                }
        }
-       
+
        if (rndis_active(dev)) {
                rndis_set_param_medium (dev->rndis_config,
                                        NDIS_MEDIUM_802_3, 0);
@@ -2301,7 +2301,7 @@ autoconf_fail:
                return -ENODEV;
        }
        in_ep->driver_data = in_ep;     /* claim */
-       
+
        out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
        if (!out_ep)
                goto autoconf_fail;
@@ -2374,8 +2374,8 @@ autoconf_fail:
 #endif
        }
 
-       net = alloc_etherdev (sizeof *dev);
-       if (!net)
+       net = alloc_etherdev (sizeof *dev);
+       if (!net)
                return status;
        dev = netdev_priv(net);
        spin_lock_init (&dev->lock);
@@ -2454,7 +2454,7 @@ autoconf_fail:
        dev->gadget = gadget;
        set_gadget_data (gadget, dev);
        gadget->ep0->driver_data = dev;
-       
+
        /* two kinds of host-initiated state changes:
         *  - iff DATA transfer is active, carrier is "on"
         *  - tx queueing enabled if open *and* carrier is "on"
@@ -2462,8 +2462,8 @@ autoconf_fail:
        netif_stop_queue (dev->net);
        netif_carrier_off (dev->net);
 
-       SET_NETDEV_DEV (dev->net, &gadget->dev);
-       status = register_netdev (dev->net);
+       SET_NETDEV_DEV (dev->net, &gadget->dev);
+       status = register_netdev (dev->net);
        if (status < 0)
                goto fail1;
 
@@ -2488,7 +2488,7 @@ autoconf_fail:
                u32     vendorID = 0;
 
                /* FIXME RNDIS vendor id == "vendor NIC code" == ? */
-               
+
                dev->rndis_config = rndis_register (rndis_control_ack);
                if (dev->rndis_config < 0) {
 fail0:
@@ -2496,7 +2496,7 @@ fail0:
                        status = -ENODEV;
                        goto fail;
                }
-               
+
                /* these set up a lot of the OIDs that RNDIS needs */
                rndis_set_host_mac (dev->rndis_config, dev->host_mac);
                if (rndis_set_param_dev (dev->rndis_config, dev->net,
@@ -2556,7 +2556,7 @@ static struct usb_gadget_driver eth_driver = {
        .suspend        = eth_suspend,
        .resume         = eth_resume,
 
-       .driver         = {
+       .driver = {
                .name           = (char *) shortname,
                .owner          = THIS_MODULE,
        },
index 0eb010a3f5bc331d52e4fc4c3819eeca57e897d2..aef0722b8f170104a898e2d556b6e67bba8418fb 100644 (file)
@@ -528,7 +528,7 @@ struct kiocb_priv {
        struct usb_request      *req;
        struct ep_data          *epdata;
        void                    *buf;
-       char __user             *ubuf;
+       char __user             *ubuf;          /* NULL for writes */
        unsigned                actual;
 };
 
@@ -566,7 +566,6 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
                status = priv->actual;
        kfree(priv->buf);
        kfree(priv);
-       aio_put_req(iocb);
        return status;
 }
 
@@ -580,8 +579,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
        spin_lock(&epdata->dev->lock);
        priv->req = NULL;
        priv->epdata = NULL;
-       if (NULL == iocb->ki_retry
-                       || unlikely(0 == req->actual)
+       if (priv->ubuf == NULL
+                       || unlikely(req->actual == 0)
                        || unlikely(kiocbIsCancelled(iocb))) {
                kfree(req->buf);
                kfree(priv);
@@ -618,7 +617,7 @@ ep_aio_rwtail(
        char __user     *ubuf
 )
 {
-       struct kiocb_priv       *priv = (void *) &iocb->private;
+       struct kiocb_priv       *priv;
        struct usb_request      *req;
        ssize_t                 value;
 
@@ -670,7 +669,7 @@ fail:
                kfree(priv);
                put_ep(epdata);
        } else
-               value = -EIOCBQUEUED;
+               value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED);
        return value;
 }
 
@@ -1039,7 +1038,7 @@ scan:
                /* ep0 can't deliver events when STATE_SETUP */
                for (i = 0; i < n; i++) {
                        if (dev->event [i].type == GADGETFS_SETUP) {
-                               len = n = i + 1;
+                               len = i + 1;
                                len *= sizeof (struct usb_gadgetfs_event);
                                n = 0;
                                break;
@@ -1587,13 +1586,13 @@ gadgetfs_create_file (struct super_block *sb, char const *name,
 static int activate_ep_files (struct dev_data *dev)
 {
        struct usb_ep   *ep;
+       struct ep_data  *data;
 
        gadget_for_each_ep (ep, dev->gadget) {
-               struct ep_data  *data;
 
                data = kzalloc(sizeof(*data), GFP_KERNEL);
                if (!data)
-                       goto enomem;
+                       goto enomem0;
                data->state = STATE_EP_DISABLED;
                init_MUTEX (&data->lock);
                init_waitqueue_head (&data->wait);
@@ -1608,21 +1607,23 @@ static int activate_ep_files (struct dev_data *dev)
 
                data->req = usb_ep_alloc_request (ep, GFP_KERNEL);
                if (!data->req)
-                       goto enomem;
+                       goto enomem1;
 
                data->inode = gadgetfs_create_file (dev->sb, data->name,
                                data, &ep_config_operations,
                                &data->dentry);
-               if (!data->inode) {
-                       usb_ep_free_request(ep, data->req);
-                       kfree (data);
-                       goto enomem;
-               }
+               if (!data->inode)
+                       goto enomem2;
                list_add_tail (&data->epfiles, &dev->epfiles);
        }
        return 0;
 
-enomem:
+enomem2:
+       usb_ep_free_request (ep, data->req);
+enomem1:
+       put_dev (dev);
+       kfree (data);
+enomem0:
        DBG (dev, "%s enomem\n", __FUNCTION__);
        destroy_ep_files (dev);
        return -ENOMEM;
@@ -1793,7 +1794,7 @@ static struct usb_gadget_driver probe_driver = {
  *
  * After initialization, the device stays active for as long as that
  * $CHIP file is open.  Events may then be read from that descriptor,
- * such configuration notifications.  More complex drivers will handle
+ * such as configuration notifications.  More complex drivers will handle
  * some control requests in user space.
  */
 
@@ -2033,12 +2034,10 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
                        NULL, &simple_dir_operations,
                        S_IFDIR | S_IRUGO | S_IXUGO);
        if (!inode)
-               return -ENOMEM;
+               goto enomem0;
        inode->i_op = &simple_dir_inode_operations;
-       if (!(d = d_alloc_root (inode))) {
-               iput (inode);
-               return -ENOMEM;
-       }
+       if (!(d = d_alloc_root (inode)))
+               goto enomem1;
        sb->s_root = d;
 
        /* the ep0 file is named after the controller we expect;
@@ -2046,21 +2045,28 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
         */
        dev = dev_new ();
        if (!dev)
-               return -ENOMEM;
+               goto enomem2;
 
        dev->sb = sb;
-       if (!(inode = gadgetfs_create_file (sb, CHIP,
+       if (!gadgetfs_create_file (sb, CHIP,
                                dev, &dev_init_operations,
-                               &dev->dentry))) {
-               put_dev(dev);
-               return -ENOMEM;
-       }
+                               &dev->dentry))
+               goto enomem3;
 
        /* other endpoint files are available after hardware setup,
         * from binding to a controller.
         */
        the_device = dev;
        return 0;
+
+enomem3:
+       put_dev (dev);
+enomem2:
+       dput (d);
+enomem1:
+       iput (inode);
+enomem0:
+       return -ENOMEM;
 }
 
 /* "mount -t gadgetfs path /dev/gadget" ends up here */
index 020d3c42b1af047297113b5c1950a3908f1d4202..1facdea56a8a54140d72f4a5d9063fb95cffe003 100644 (file)
@@ -2966,6 +2966,22 @@ done:
        return retval;
 }
 
+/* make sure the board is quiescent; otherwise it will continue
+ * generating IRQs across the upcoming reboot.
+ */
+
+static void net2280_shutdown (struct pci_dev *pdev)
+{
+       struct net2280          *dev = pci_get_drvdata (pdev);
+
+       /* disable IRQs */
+       writel (0, &dev->regs->pciirqenb0);
+       writel (0, &dev->regs->pciirqenb1);
+
+       /* disable the pullup so the host will think we're gone */
+       writel (0, &dev->usb->usbctl);
+}
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -2995,6 +3011,7 @@ static struct pci_driver net2280_pci_driver = {
 
        .probe =        net2280_probe,
        .remove =       net2280_remove,
+       .shutdown =     net2280_shutdown,
 
        /* FIXME add power management support */
 };
index 680f7fc5b1717addba266f385e33a7b209ee1d7e..269ce7f4ad6608f56ab79aeb1e7e3a0d97593bc3 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
+#ifdef CONFIG_ARCH_PXA
 #include <asm/arch/pxa-regs.h>
+#endif
 
 #include <linux/usb_ch9.h>
 #include <linux/usb_gadget.h>
 
-#include <asm/arch/udc.h>
+#include <asm/arch/hardware/intel_udc.h>
 
 
 /*
@@ -545,6 +547,7 @@ write_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
                count = req->req.length;
                done (ep, req, 0);
                ep0_idle(ep->dev);
+#ifndef CONFIG_ARCH_IXP4XX
 #if 1
                /* This seems to get rid of lost status irqs in some cases:
                 * host responds quickly, or next request involves config
@@ -564,6 +567,7 @@ write_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
                                udelay(1);
                        } while (count);
                }
+#endif
 #endif
        } else if (ep->dev->req_pending)
                ep0start(ep->dev, 0, "IN");
@@ -1585,7 +1589,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
        int                     retval;
 
        if (!driver
-                       || driver->speed != USB_SPEED_FULL
+                       || driver->speed < USB_SPEED_FULL
                        || !driver->bind
                        || !driver->unbind
                        || !driver->disconnect
@@ -2427,6 +2431,7 @@ static struct pxa2xx_udc memory = {
 #define PXA210_B1              0x00000123
 #define PXA210_B0              0x00000122
 #define IXP425_A0              0x000001c1
+#define IXP465_AD              0x00000200
 
 /*
  *     probe - binds to the platform device
@@ -2463,6 +2468,8 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
                break;
 #elif  defined(CONFIG_ARCH_IXP4XX)
        case IXP425_A0:
+       case IXP465_AD:
+               dev->has_cfr = 1;
                out_dma = 0;
                break;
 #endif
@@ -2575,10 +2582,12 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
                free_irq(IRQ_USB, dev);
                dev->got_irq = 0;
        }
+#ifdef CONFIG_ARCH_LUBBOCK
        if (machine_is_lubbock()) {
                free_irq(LUBBOCK_USB_DISC_IRQ, dev);
                free_irq(LUBBOCK_USB_IRQ, dev);
        }
+#endif
        platform_set_drvdata(pdev, NULL);
        the_controller = NULL;
        return 0;
index 6d6eaad73968caa6af45521858b4b1287231041e..3ff6db7828a04560eaf963f6ec77eec9d14dd2a3 100644 (file)
@@ -1,23 +1,23 @@
-/* 
+/*
  * RNDIS MSG parser
- * 
+ *
  * Version:     $Id: rndis.c,v 1.19 2004/03/25 21:33:46 robert Exp $
- * 
+ *
  * Authors:    Benedikt Spranger, Pengutronix
- *             Robert Schwebel, Pengutronix
- * 
+ *             Robert Schwebel, Pengutronix
+ *
  *              This program is free software; you can redistribute it and/or
  *              modify it under the terms of the GNU General Public License
- *              version 2, as published by the Free Software Foundation. 
- * 
+ *              version 2, as published by the Free Software Foundation.
+ *
  *             This software was originally developed in conformance with
  *             Microsoft's Remote NDIS Specification License Agreement.
- *              
+ *
  * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
  *             Fixed message length bug in init_response
- * 
+ *
  * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
- *             Fixed rndis_rm_hdr length bug.
+ *             Fixed rndis_rm_hdr length bug.
  *
  * Copyright (C) 2004 by David Brownell
  *             updates to merge with Linux 2.6, better match RNDIS spec
@@ -82,7 +82,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length);
 
 
 /* supported OIDs */
-static const u32 oid_supported_list [] = 
+static const u32 oid_supported_list [] =
 {
        /* the general stuff */
        OID_GEN_SUPPORTED_LIST,
@@ -103,7 +103,7 @@ static const u32 oid_supported_list [] =
 #if 0
        OID_GEN_RNDIS_CONFIG_PARAMETER,
 #endif
-       
+
        /* the statistical stuff */
        OID_GEN_XMIT_OK,
        OID_GEN_RCV_OK,
@@ -127,14 +127,14 @@ static const u32 oid_supported_list [] =
        OID_GEN_TRANSMIT_QUEUE_LENGTH,
 #endif /* RNDIS_OPTIONAL_STATS */
 
-       /* mandatory 802.3 */
+       /* mandatory 802.3 */
        /* the general stuff */
        OID_802_3_PERMANENT_ADDRESS,
        OID_802_3_CURRENT_ADDRESS,
        OID_802_3_MULTICAST_LIST,
        OID_802_3_MAC_OPTIONS,
        OID_802_3_MAXIMUM_LIST_SIZE,
-       
+
        /* the statistical stuff */
        OID_802_3_RCV_ERROR_ALIGNMENT,
        OID_802_3_XMIT_ONE_COLLISION,
@@ -172,8 +172,8 @@ static int
 gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                rndis_resp_t *r)
 {
-       int                     retval = -ENOTSUPP;
-       u32                     length = 4;     /* usually */
+       int                     retval = -ENOTSUPP;
+       u32                     length = 4;     /* usually */
        __le32                  *outbuf;
        int                     i, count;
        rndis_query_cmplt_type  *resp;
@@ -211,27 +211,27 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
                retval = 0;
                break;
-               
+
        /* mandatory */
        case OID_GEN_HARDWARE_STATUS:
                DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
-               /* Bogus question! 
+               /* Bogus question!
                 * Hardware must be ready to receive high level protocols.
-                * BTW: 
+                * BTW:
                 * reddite ergo quae sunt Caesaris Caesari
                 * et quae sunt Dei Deo!
                 */
                *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
-               
+
        /* mandatory */
        case OID_GEN_MEDIA_SUPPORTED:
                DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
                *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
                retval = 0;
                break;
-               
+
        /* mandatory */
        case OID_GEN_MEDIA_IN_USE:
                DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
@@ -239,7 +239,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
                retval = 0;
                break;
-               
+
        /* mandatory */
        case OID_GEN_MAXIMUM_FRAME_SIZE:
                DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
@@ -249,7 +249,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_GEN_LINK_SPEED:
                if (rndis_debug > 1)
@@ -272,7 +272,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_GEN_RECEIVE_BLOCK_SIZE:
                DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
@@ -282,7 +282,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_GEN_VENDOR_ID:
                DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
@@ -290,7 +290,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        rndis_per_dev_params [configNr].vendorID);
                retval = 0;
                break;
-               
+
        /* mandatory */
        case OID_GEN_VENDOR_DESCRIPTION:
                DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
@@ -356,7 +356,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
                        *outbuf = cpu_to_le32 (
-                           rndis_per_dev_params [configNr].stats->tx_packets - 
+                           rndis_per_dev_params [configNr].stats->tx_packets -
                            rndis_per_dev_params [configNr].stats->tx_errors -
                            rndis_per_dev_params [configNr].stats->tx_dropped);
                        retval = 0;
@@ -369,13 +369,13 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
                        *outbuf = cpu_to_le32 (
-                           rndis_per_dev_params [configNr].stats->rx_packets - 
+                           rndis_per_dev_params [configNr].stats->rx_packets -
                            rndis_per_dev_params [configNr].stats->rx_errors -
                            rndis_per_dev_params [configNr].stats->rx_dropped);
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_GEN_XMIT_ERROR:
                if (rndis_debug > 1)
@@ -386,7 +386,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_GEN_RCV_ERROR:
                if (rndis_debug > 1)
@@ -397,7 +397,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_GEN_RCV_NO_BUFFER:
                DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
@@ -411,7 +411,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 #ifdef RNDIS_OPTIONAL_STATS
        case OID_GEN_DIRECTED_BYTES_XMIT:
                DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
-               /* 
+               /*
                 * Aunt Tilly's size of shoes
                 * minus antarctica count of penguins
                 * divided by weight of Alpha Centauri
@@ -419,7 +419,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                if (rndis_per_dev_params [configNr].stats) {
                        *outbuf = cpu_to_le32 (
                                (rndis_per_dev_params [configNr]
-                                       .stats->tx_packets - 
+                                       .stats->tx_packets -
                                 rndis_per_dev_params [configNr]
                                         .stats->tx_errors -
                                 rndis_per_dev_params [configNr]
@@ -428,14 +428,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_DIRECTED_FRAMES_XMIT:
                DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
                /* dito */
                if (rndis_per_dev_params [configNr].stats) {
                        *outbuf = cpu_to_le32 (
                                (rndis_per_dev_params [configNr]
-                                       .stats->tx_packets - 
+                                       .stats->tx_packets -
                                 rndis_per_dev_params [configNr]
                                         .stats->tx_errors -
                                 rndis_per_dev_params [configNr]
@@ -444,7 +444,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_MULTICAST_BYTES_XMIT:
                DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -453,7 +453,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_MULTICAST_FRAMES_XMIT:
                DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -462,7 +462,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_BROADCAST_BYTES_XMIT:
                DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -471,7 +471,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_BROADCAST_FRAMES_XMIT:
                DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -480,19 +480,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_DIRECTED_BYTES_RCV:
                DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
                *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
-               
+
        case OID_GEN_DIRECTED_FRAMES_RCV:
                DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
                *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
-               
+
        case OID_GEN_MULTICAST_BYTES_RCV:
                DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -501,7 +501,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_MULTICAST_FRAMES_RCV:
                DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -510,7 +510,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_BROADCAST_BYTES_RCV:
                DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -519,7 +519,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_BROADCAST_FRAMES_RCV:
                DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -528,7 +528,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_RCV_CRC_ERROR:
                DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
                if (rndis_per_dev_params [configNr].stats) {
@@ -537,7 +537,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        case OID_GEN_TRANSMIT_QUEUE_LENGTH:
                DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
                *outbuf = __constant_cpu_to_le32 (0);
@@ -558,7 +558,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_802_3_CURRENT_ADDRESS:
                DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
@@ -570,7 +570,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_802_3_MULTICAST_LIST:
                DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
@@ -578,7 +578,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                *outbuf = __constant_cpu_to_le32 (0xE0000000);
                retval = 0;
                break;
-               
+
        /* mandatory */
        case OID_802_3_MAXIMUM_LIST_SIZE:
                DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
@@ -586,7 +586,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                *outbuf = __constant_cpu_to_le32 (1);
                retval = 0;
                break;
-               
+
        case OID_802_3_MAC_OPTIONS:
                DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
                break;
@@ -602,56 +602,56 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
                        retval = 0;
                }
                break;
-               
+
        /* mandatory */
        case OID_802_3_XMIT_ONE_COLLISION:
                DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
                *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
-               
+
        /* mandatory */
        case OID_802_3_XMIT_MORE_COLLISIONS:
                DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
                *outbuf = __constant_cpu_to_le32 (0);
                retval = 0;
                break;
-               
+
 #ifdef RNDIS_OPTIONAL_STATS
        case OID_802_3_XMIT_DEFERRED:
                DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
                /* TODO */
                break;
-               
+
        case OID_802_3_XMIT_MAX_COLLISIONS:
                DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
                /* TODO */
                break;
-               
+
        case OID_802_3_RCV_OVERRUN:
                DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
                /* TODO */
                break;
-               
+
        case OID_802_3_XMIT_UNDERRUN:
                DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
                /* TODO */
                break;
-               
+
        case OID_802_3_XMIT_HEARTBEAT_FAILURE:
                DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
                /* TODO */
                break;
-               
+
        case OID_802_3_XMIT_TIMES_CRS_LOST:
                DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
                /* TODO */
                break;
-               
+
        case OID_802_3_XMIT_LATE_COLLISIONS:
                DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
                /* TODO */
-               break;          
+               break;
 #endif /* RNDIS_OPTIONAL_STATS */
 
 #ifdef RNDIS_PM
@@ -676,23 +676,23 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 #endif
 
        default:
-               printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", 
+               printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
                         __FUNCTION__, OID);
        }
        if (retval < 0)
                length = 0;
-       
+
        resp->InformationBufferLength = cpu_to_le32 (length);
        r->length = length + sizeof *resp;
        resp->MessageLength = cpu_to_le32 (r->length);
        return retval;
 }
 
-static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, 
-                             rndis_resp_t *r)
+static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
+                       rndis_resp_t *r)
 {
        rndis_set_cmplt_type            *resp;
-       int                             i, retval = -ENOTSUPP;
+       int                             i, retval = -ENOTSUPP;
        struct rndis_params             *params;
 
        if (!r)
@@ -745,9 +745,9 @@ update_linkstate:
                        netif_stop_queue (params->dev);
                }
                break;
-               
+
        case OID_802_3_MULTICAST_LIST:
-               /* I think we can ignore this */                
+               /* I think we can ignore this */
                DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
                retval = 0;
                break;
@@ -796,29 +796,29 @@ update_linkstate:
 #endif /* RNDIS_PM */
 
        default:
-               printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", 
+               printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
                         __FUNCTION__, OID, buf_len);
        }
-       
+
        return retval;
 }
 
-/* 
- * Response Functions 
+/*
+ * Response Functions
  */
 
 static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
 {
-       rndis_init_cmplt_type   *resp; 
+       rndis_init_cmplt_type   *resp;
        rndis_resp_t            *r;
-       
+
        if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
-       
+
        r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_init_cmplt_type *) r->buf;
-       
+
        resp->MessageType = __constant_cpu_to_le32 (
                        REMOTE_NDIS_INITIALIZE_CMPLT);
        resp->MessageLength = __constant_cpu_to_le32 (52);
@@ -837,11 +837,11 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
        resp->PacketAlignmentFactor = __constant_cpu_to_le32 (0);
        resp->AFListOffset = __constant_cpu_to_le32 (0);
        resp->AFListSize = __constant_cpu_to_le32 (0);
-       
+
        if (rndis_per_dev_params [configNr].ack)
-           rndis_per_dev_params [configNr].ack (
-                       rndis_per_dev_params [configNr].dev);
-       
+               rndis_per_dev_params [configNr].ack (
+                       rndis_per_dev_params [configNr].dev);
+
        return 0;
 }
 
@@ -849,10 +849,10 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
 {
        rndis_query_cmplt_type *resp;
        rndis_resp_t            *r;
-       
+
        // DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
        if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
-       
+
        /*
         * we need more memory:
         * gen_ndis_query_resp expects enough space for
@@ -864,10 +864,10 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
        if (!r)
                return -ENOMEM;
        resp = (rndis_query_cmplt_type *) r->buf;
-       
+
        resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
        resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-       
+
        if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
                        le32_to_cpu(buf->InformationBufferOffset)
                                        + 8 + (u8 *) buf,
@@ -881,10 +881,10 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
                resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
        } else
                resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
-       
+
        if (rndis_per_dev_params [configNr].ack)
-           rndis_per_dev_params [configNr].ack (
-                       rndis_per_dev_params [configNr].dev);
+               rndis_per_dev_params [configNr].ack (
+                       rndis_per_dev_params [configNr].dev);
        return 0;
 }
 
@@ -893,7 +893,7 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
        u32                     BufLength, BufOffset;
        rndis_set_cmplt_type    *resp;
        rndis_resp_t            *r;
-       
+
        r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
        if (!r)
                return -ENOMEM;
@@ -906,26 +906,27 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
        DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
        DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
        DEBUG("%s: InfoBuffer: ", __FUNCTION__);
-       
+
        for (i = 0; i < BufLength; i++) {
                DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
        }
-       
+
        DEBUG ("\n");
 #endif
-       
+
        resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
        resp->MessageLength = __constant_cpu_to_le32 (16);
        resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-       if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID), 
-                              ((u8 *) buf) + 8 + BufOffset, BufLength, r))
-           resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED);
-       else resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
-       
+       if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID),
+                       ((u8 *) buf) + 8 + BufOffset, BufLength, r))
+               resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED);
+       else
+               resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
+
        if (rndis_per_dev_params [configNr].ack)
-           rndis_per_dev_params [configNr].ack (
-                       rndis_per_dev_params [configNr].dev);
-       
+               rndis_per_dev_params [configNr].ack (
+                       rndis_per_dev_params [configNr].dev);
+
        return 0;
 }
 
@@ -933,27 +934,27 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
 {
        rndis_reset_cmplt_type  *resp;
        rndis_resp_t            *r;
-       
+
        r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_reset_cmplt_type *) r->buf;
-       
+
        resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
        resp->MessageLength = __constant_cpu_to_le32 (16);
        resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
        /* resent information */
        resp->AddressingReset = __constant_cpu_to_le32 (1);
-       
+
        if (rndis_per_dev_params [configNr].ack)
-           rndis_per_dev_params [configNr].ack (
-                       rndis_per_dev_params [configNr].dev);
+               rndis_per_dev_params [configNr].ack (
+                       rndis_per_dev_params [configNr].dev);
 
        return 0;
 }
 
 static int rndis_keepalive_response (int configNr,
-                                    rndis_keepalive_msg_type *buf)
+                               rndis_keepalive_msg_type *buf)
 {
        rndis_keepalive_cmplt_type      *resp;
        rndis_resp_t                    *r;
@@ -964,48 +965,48 @@ static int rndis_keepalive_response (int configNr,
        if (!r)
                return -ENOMEM;
        resp = (rndis_keepalive_cmplt_type *) r->buf;
-               
+
        resp->MessageType = __constant_cpu_to_le32 (
                        REMOTE_NDIS_KEEPALIVE_CMPLT);
        resp->MessageLength = __constant_cpu_to_le32 (16);
        resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
        resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
-       
+
        if (rndis_per_dev_params [configNr].ack)
-           rndis_per_dev_params [configNr].ack (
-                       rndis_per_dev_params [configNr].dev);
-       
+               rndis_per_dev_params [configNr].ack (
+                       rndis_per_dev_params [configNr].dev);
+
        return 0;
 }
 
 
-/* 
- * Device to Host Comunication 
+/*
+ * Device to Host Comunication
  */
 static int rndis_indicate_status_msg (int configNr, u32 status)
 {
-       rndis_indicate_status_msg_type  *resp;  
+       rndis_indicate_status_msg_type  *resp;
        rndis_resp_t                    *r;
-       
+
        if (rndis_per_dev_params [configNr].state == RNDIS_UNINITIALIZED)
-           return -ENOTSUPP;
-       
-       r = rndis_add_response (configNr, 
+               return -ENOTSUPP;
+
+       r = rndis_add_response (configNr,
                                sizeof (rndis_indicate_status_msg_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_indicate_status_msg_type *) r->buf;
-       
+
        resp->MessageType = __constant_cpu_to_le32 (
                        REMOTE_NDIS_INDICATE_STATUS_MSG);
        resp->MessageLength = __constant_cpu_to_le32 (20);
        resp->Status = cpu_to_le32 (status);
        resp->StatusBufferLength = __constant_cpu_to_le32 (0);
        resp->StatusBufferOffset = __constant_cpu_to_le32 (0);
-       
-       if (rndis_per_dev_params [configNr].ack) 
-           rndis_per_dev_params [configNr].ack (
-                       rndis_per_dev_params [configNr].dev);
+
+       if (rndis_per_dev_params [configNr].ack)
+               rndis_per_dev_params [configNr].ack (
+                       rndis_per_dev_params [configNr].dev);
        return 0;
 }
 
@@ -1013,7 +1014,7 @@ int rndis_signal_connect (int configNr)
 {
        rndis_per_dev_params [configNr].media_state
                        = NDIS_MEDIA_STATE_CONNECTED;
-       return rndis_indicate_status_msg (configNr, 
+       return rndis_indicate_status_msg (configNr,
                                          RNDIS_STATUS_MEDIA_CONNECT);
 }
 
@@ -1045,26 +1046,26 @@ void rndis_set_host_mac (int configNr, const u8 *addr)
        rndis_per_dev_params [configNr].host_mac = addr;
 }
 
-/* 
- * Message Parser 
+/*
+ * Message Parser
  */
 int rndis_msg_parser (u8 configNr, u8 *buf)
 {
        u32 MsgType, MsgLength;
        __le32 *tmp;
        struct rndis_params             *params;
-       
+
        if (!buf)
                return -ENOMEM;
-       
-       tmp = (__le32 *) buf; 
+
+       tmp = (__le32 *) buf;
        MsgType   = le32_to_cpup(tmp++);
        MsgLength = le32_to_cpup(tmp++);
-       
+
        if (configNr >= RNDIS_MAX_CONFIGS)
                return -ENOTSUPP;
        params = &rndis_per_dev_params [configNr];
-       
+
        /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
         * rx/tx statistics and link status, in addition to KEEPALIVE traffic
         * and normal HC level polling to see if there's any IN traffic.
@@ -1073,12 +1074,12 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
        /* For USB: responses may take up to 10 seconds */
        switch (MsgType) {
        case REMOTE_NDIS_INITIALIZE_MSG:
-               DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", 
+               DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
                        __FUNCTION__ );
                params->state = RNDIS_INITIALIZED;
                return  rndis_init_response (configNr,
-                                            (rndis_init_msg_type *) buf);
-               
+                                       (rndis_init_msg_type *) buf);
+
        case REMOTE_NDIS_HALT_MSG:
                DEBUG("%s: REMOTE_NDIS_HALT_MSG\n",
                        __FUNCTION__ );
@@ -1088,37 +1089,37 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
                        netif_stop_queue (params->dev);
                }
                return 0;
-               
+
        case REMOTE_NDIS_QUERY_MSG:
-               return rndis_query_response (configNr, 
-                                            (rndis_query_msg_type *) buf);
-               
+               return rndis_query_response (configNr,
+                                       (rndis_query_msg_type *) buf);
+
        case REMOTE_NDIS_SET_MSG:
-               return rndis_set_response (configNr, 
-                                          (rndis_set_msg_type *) buf);
-               
+               return rndis_set_response (configNr,
+                                       (rndis_set_msg_type *) buf);
+
        case REMOTE_NDIS_RESET_MSG:
-               DEBUG("%s: REMOTE_NDIS_RESET_MSG\n", 
+               DEBUG("%s: REMOTE_NDIS_RESET_MSG\n",
                        __FUNCTION__ );
                return rndis_reset_response (configNr,
-                                            (rndis_reset_msg_type *) buf);
+                                       (rndis_reset_msg_type *) buf);
 
        case REMOTE_NDIS_KEEPALIVE_MSG:
                /* For USB: host does this every 5 seconds */
                if (rndis_debug > 1)
-                       DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
+                       DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
                                __FUNCTION__ );
                return rndis_keepalive_response (configNr,
-                                                (rndis_keepalive_msg_type *) 
+                                                (rndis_keepalive_msg_type *)
                                                 buf);
-               
-       default: 
+
+       default:
                /* At least Windows XP emits some undefined RNDIS messages.
                 * In one case those messages seemed to relate to the host
                 * suspending itself.
                 */
                printk (KERN_WARNING
-                       "%s: unknown RNDIS message 0x%08X len %d\n", 
+                       "%s: unknown RNDIS message 0x%08X len %d\n",
                        __FUNCTION__ , MsgType, MsgLength);
                {
                        unsigned i;
@@ -1142,14 +1143,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
                }
                break;
        }
-       
+
        return -ENOTSUPP;
 }
 
 int rndis_register (int (* rndis_control_ack) (struct net_device *))
 {
        u8 i;
-       
+
        for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
                if (!rndis_per_dev_params [i].used) {
                        rndis_per_dev_params [i].used = 1;
@@ -1159,32 +1160,32 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *))
                }
        }
        DEBUG("failed\n");
-       
+
        return -1;
 }
 
 void rndis_deregister (int configNr)
 {
        DEBUG("%s: \n", __FUNCTION__ );
-       
+
        if (configNr >= RNDIS_MAX_CONFIGS) return;
        rndis_per_dev_params [configNr].used = 0;
-       
+
        return;
 }
 
-int rndis_set_param_dev (u8 configNr, struct net_device *dev, 
+int rndis_set_param_dev (u8 configNr, struct net_device *dev,
                         struct net_device_stats *stats,
                         u16 *cdc_filter)
 {
        DEBUG("%s:\n", __FUNCTION__ );
        if (!dev || !stats) return -1;
        if (configNr >= RNDIS_MAX_CONFIGS) return -1;
-       
+
        rndis_per_dev_params [configNr].dev = dev;
        rndis_per_dev_params [configNr].stats = stats;
        rndis_per_dev_params [configNr].filter = cdc_filter;
-       
+
        return 0;
 }
 
@@ -1193,10 +1194,10 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
        DEBUG("%s:\n", __FUNCTION__ );
        if (!vendorDescr) return -1;
        if (configNr >= RNDIS_MAX_CONFIGS) return -1;
-       
+
        rndis_per_dev_params [configNr].vendorID = vendorID;
        rndis_per_dev_params [configNr].vendorDescr = vendorDescr;
-       
+
        return 0;
 }
 
@@ -1204,10 +1205,10 @@ int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
 {
        DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
        if (configNr >= RNDIS_MAX_CONFIGS) return -1;
-       
+
        rndis_per_dev_params [configNr].medium = medium;
        rndis_per_dev_params [configNr].speed = speed;
-       
+
        return 0;
 }
 
@@ -1229,9 +1230,9 @@ void rndis_free_response (int configNr, u8 *buf)
 {
        rndis_resp_t            *r;
        struct list_head        *act, *tmp;
-       
-       list_for_each_safe (act, tmp, 
-                           &(rndis_per_dev_params [configNr].resp_queue))
+
+       list_for_each_safe (act, tmp,
+                       &(rndis_per_dev_params [configNr].resp_queue))
        {
                r = list_entry (act, rndis_resp_t, list);
                if (r && r->buf == buf) {
@@ -1244,12 +1245,12 @@ void rndis_free_response (int configNr, u8 *buf)
 u8 *rndis_get_next_response (int configNr, u32 *length)
 {
        rndis_resp_t            *r;
-       struct list_head        *act, *tmp;
-       
+       struct list_head        *act, *tmp;
+
        if (!length) return NULL;
-       
-       list_for_each_safe (act, tmp, 
-                           &(rndis_per_dev_params [configNr].resp_queue))
+
+       list_for_each_safe (act, tmp,
+                       &(rndis_per_dev_params [configNr].resp_queue))
        {
                r = list_entry (act, rndis_resp_t, list);
                if (!r->send) {
@@ -1258,24 +1259,24 @@ u8 *rndis_get_next_response (int configNr, u32 *length)
                        return r->buf;
                }
        }
-       
+
        return NULL;
 }
 
 static rndis_resp_t *rndis_add_response (int configNr, u32 length)
 {
        rndis_resp_t    *r;
-       
+
        /* NOTE:  this gets copied into ether.c USB_BUFSIZ bytes ... */
        r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
        if (!r) return NULL;
-       
+
        r->buf = (u8 *) (r + 1);
        r->length = length;
        r->send = 0;
-       
-       list_add_tail (&r->list, 
-                      &(rndis_per_dev_params [configNr].resp_queue));
+
+       list_add_tail (&r->list,
+               &(rndis_per_dev_params [configNr].resp_queue));
        return r;
 }
 
@@ -1301,14 +1302,14 @@ int rndis_rm_hdr(struct sk_buff *skb)
 
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 
-static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, 
-                    void *data)
+static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
+               void *data)
 {
        char *out = page;
        int len;
        rndis_params *param = (rndis_params *) data;
-       
-       out += snprintf (out, count, 
+
+       out += snprintf (out, count,
                         "Config Nr. %d\n"
                         "used      : %s\n"
                         "state     : %s\n"
@@ -1316,8 +1317,8 @@ static int rndis_proc_read (char *page, char **start, off_t off, int count, int
                         "speed     : %d\n"
                         "cable     : %s\n"
                         "vendor ID : 0x%08X\n"
-                        "vendor    : %s\n", 
-                        param->confignr, (param->used) ? "y" : "n", 
+                        "vendor    : %s\n",
+                        param->confignr, (param->used) ? "y" : "n",
                         ({ char *s = "?";
                         switch (param->state) {
                         case RNDIS_UNINITIALIZED:
@@ -1327,32 +1328,32 @@ static int rndis_proc_read (char *page, char **start, off_t off, int count, int
                         case RNDIS_DATA_INITIALIZED:
                                s = "RNDIS_DATA_INITIALIZED"; break;
                        }; s; }),
-                        param->medium, 
-                        (param->media_state) ? 0 : param->speed*100, 
+                        param->medium,
+                        (param->media_state) ? 0 : param->speed*100,
                         (param->media_state) ? "disconnected" : "connected",
-                        param->vendorID, param->vendorDescr);      
-       
+                        param->vendorID, param->vendorDescr);
+
        len = out - page;
        len -= off;
-       
+
        if (len < count) {
                *eof = 1;
                if (len <= 0)
                        return 0;
        } else
                len = count;
-       
+
        *start = page + off;
        return len;
 }
 
-static int rndis_proc_write (struct file *file, const char __user *buffer, 
-                     unsigned long count, void *data)
+static int rndis_proc_write (struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
 {
        rndis_params *p = data;
        u32 speed = 0;
        int i, fl_speed = 0;
-       
+
        for (i = 0; i < count; i++) {
                char c;
                if (get_user(c, buffer))
@@ -1379,15 +1380,15 @@ static int rndis_proc_write (struct file *file, const char __user *buffer,
                case 'd':
                        rndis_signal_disconnect(p->confignr);
                        break;
-               default: 
+               default:
                        if (fl_speed) p->speed = speed;
                        else DEBUG ("%c is not valid\n", c);
                        break;
                }
-               
+
                buffer++;
        }
-       
+
        return count;
 }
 
@@ -1408,7 +1409,7 @@ int __init rndis_init (void)
 
                sprintf (name, NAME_TEMPLATE, i);
                if (!(rndis_connect_state [i]
-                               = create_proc_entry (name, 0660, NULL))) 
+                               = create_proc_entry (name, 0660, NULL)))
                {
                        DEBUG ("%s :remove entries", __FUNCTION__);
                        while (i) {
@@ -1432,7 +1433,7 @@ int __init rndis_init (void)
                                = NDIS_MEDIA_STATE_DISCONNECTED;
                INIT_LIST_HEAD (&(rndis_per_dev_params [i].resp_queue));
        }
-       
+
        return 0;
 }
 
@@ -1441,7 +1442,7 @@ void rndis_exit (void)
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
        u8 i;
        char name [20];
-       
+
        for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
                sprintf (name, NAME_TEMPLATE, i);
                remove_proc_entry (name, NULL);
index 95b4c63261000b15d8c0a0dff21aa48ab720232f..2956608be751f70095bfb8ff8d2890b05060ecee 100644 (file)
@@ -1,15 +1,15 @@
-/* 
+/*
  * RNDIS       Definitions for Remote NDIS
- * 
+ *
  * Version:    $Id: rndis.h,v 1.15 2004/03/25 21:33:46 robert Exp $
- * 
+ *
  * Authors:    Benedikt Spranger, Pengutronix
- *             Robert Schwebel, Pengutronix
- * 
- *             This program is free software; you can redistribute it and/or
+ *             Robert Schwebel, Pengutronix
+ *
+ *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
- *             version 2, as published by the Free Software Foundation. 
- * 
+ *             version 2, as published by the Free Software Foundation.
+ *
  *             This software was originally developed in conformance with
  *             Microsoft's Remote NDIS Specification License Agreement.
  */
@@ -34,7 +34,7 @@
 #define RNDIS_STATUS_MEDIA_CONNECT     0x4001000BU     /* Device connected  */
 #define RNDIS_STATUS_MEDIA_DISCONNECT  0x4001000CU     /* Device disconnected */
 /* For all not specified status messages:
- * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx 
+ * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx
  */
 
 /* Message Set for Connectionless (802.3) Devices */
@@ -69,7 +69,7 @@
 #define OID_PNP_ENABLE_WAKE_UP                 0xFD010106
 
 
-typedef struct rndis_init_msg_type 
+typedef struct rndis_init_msg_type
 {
        __le32  MessageType;
        __le32  MessageLength;
@@ -234,12 +234,12 @@ typedef struct rndis_params
 
        const u8                *host_mac;
        u16                     *filter;
-       struct net_device       *dev;
+       struct net_device       *dev;
        struct net_device_stats *stats;
 
        u32                     vendorID;
        const char              *vendorDescr;
-       int                     (*ack) (struct net_device *);
+       int                     (*ack) (struct net_device *);
        struct list_head        resp_queue;
 } rndis_params;
 
@@ -250,7 +250,7 @@ void rndis_deregister (int configNr);
 int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
                         struct net_device_stats *stats,
                         u16 *cdc_filter);
-int  rndis_set_param_vendor (u8 configNr, u32 vendorID, 
+int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
                            const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
 void rndis_add_hdr (struct sk_buff *skb);
index b992546c394d5c1e5aac6dd823d6875d506b9846..9d6e1d295528f5e30a17d5d3360ef6092cd56f55 100644 (file)
 #include <asm/uaccess.h>
 
 #include <linux/usb_ch9.h>
-#include <linux/usb_cdc.h>
+#include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
 
 
-/* Wait Cond */
-
-#define __wait_cond_interruptible(wq, condition, lock, flags, ret)     \
-do {                                                                   \
-       wait_queue_t __wait;                                            \
-       init_waitqueue_entry(&__wait, current);                         \
-                                                                       \
-       add_wait_queue(&wq, &__wait);                                   \
-       for (;;) {                                                      \
-               set_current_state(TASK_INTERRUPTIBLE);                  \
-               if (condition)                                          \
-                       break;                                          \
-               if (!signal_pending(current)) {                         \
-                       spin_unlock_irqrestore(lock, flags);            \
-                       schedule();                                     \
-                       spin_lock_irqsave(lock, flags);                 \
-                       continue;                                       \
-               }                                                       \
-               ret = -ERESTARTSYS;                                     \
-               break;                                                  \
-       }                                                               \
-       current->state = TASK_RUNNING;                                  \
-       remove_wait_queue(&wq, &__wait);                                \
-} while (0)
-       
-#define wait_cond_interruptible(wq, condition, lock, flags)            \
-({                                                                     \
-       int __ret = 0;                                                  \
-       if (!(condition))                                               \
-               __wait_cond_interruptible(wq, condition, lock, flags,   \
-                                               __ret);                 \
-       __ret;                                                          \
-})
-
-#define __wait_cond_interruptible_timeout(wq, condition, lock, flags,  \
-                                               timeout, ret)           \
-do {                                                                   \
-       signed long __timeout = timeout;                                \
-       wait_queue_t __wait;                                            \
-       init_waitqueue_entry(&__wait, current);                         \
-                                                                       \
-       add_wait_queue(&wq, &__wait);                                   \
-       for (;;) {                                                      \
-               set_current_state(TASK_INTERRUPTIBLE);                  \
-               if (__timeout == 0)                                     \
-                       break;                                          \
-               if (condition)                                          \
-                       break;                                          \
-               if (!signal_pending(current)) {                         \
-                       spin_unlock_irqrestore(lock, flags);            \
-                       __timeout = schedule_timeout(__timeout);        \
-                       spin_lock_irqsave(lock, flags);                 \
-                       continue;                                       \
-               }                                                       \
-               ret = -ERESTARTSYS;                                     \
-               break;                                                  \
-       }                                                               \
-       current->state = TASK_RUNNING;                                  \
-       remove_wait_queue(&wq, &__wait);                                \
-} while (0)
-       
-#define wait_cond_interruptible_timeout(wq, condition, lock, flags,    \
-                                               timeout)                \
-({                                                                     \
-       int __ret = 0;                                                  \
-       if (!(condition))                                               \
-               __wait_cond_interruptible_timeout(wq, condition, lock,  \
-                                               flags, timeout, __ret); \
-       __ret;                                                          \
-})
-
-
 /* Defines */
 
-#define GS_VERSION_STR                 "v2.0"
-#define GS_VERSION_NUM                 0x0200
+#define GS_VERSION_STR                 "v2.2"
+#define GS_VERSION_NUM                 0x0202
 
 #define GS_LONG_NAME                   "Gadget Serial"
 #define GS_SHORT_NAME                  "g_serial"
@@ -843,9 +771,19 @@ exit_unlock_dev:
 /*
  * gs_close
  */
+
+#define GS_WRITE_FINISHED_EVENT_SAFELY(p)                      \
+({                                                             \
+       int cond;                                               \
+                                                               \
+       spin_lock_irq(&(p)->port_lock);                         \
+       cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf); \
+       spin_unlock_irq(&(p)->port_lock);                       \
+       cond;                                                   \
+})
+
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
-       unsigned long flags;
        struct gs_port *port = tty->driver_data;
        struct semaphore *sem;
 
@@ -859,7 +797,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        sem = &gs_open_close_sem[port->port_num];
        down(sem);
 
-       spin_lock_irqsave(&port->port_lock, flags);
+       spin_lock_irq(&port->port_lock);
 
        if (port->port_open_count == 0) {
                printk(KERN_ERR
@@ -887,12 +825,11 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        /* wait for write buffer to drain, or */
        /* at most GS_CLOSE_TIMEOUT seconds */
        if (gs_buf_data_avail(port->port_write_buf) > 0) {
-               spin_unlock_irqrestore(&port->port_lock, flags);
-               wait_cond_interruptible_timeout(port->port_write_wait,
-               port->port_dev == NULL
-               || gs_buf_data_avail(port->port_write_buf) == 0,
-               &port->port_lock, flags, GS_CLOSE_TIMEOUT * HZ);
-               spin_lock_irqsave(&port->port_lock, flags);
+               spin_unlock_irq(&port->port_lock);
+               wait_event_interruptible_timeout(port->port_write_wait,
+                                       GS_WRITE_FINISHED_EVENT_SAFELY(port),
+                                       GS_CLOSE_TIMEOUT * HZ);
+               spin_lock_irq(&port->port_lock);
        }
 
        /* free disconnected port on final close */
@@ -912,7 +849,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
                port->port_num, tty, file);
 
 exit:
-       spin_unlock_irqrestore(&port->port_lock, flags);
+       spin_unlock_irq(&port->port_lock);
        up(sem);
 }
 
index e27b79a3c05f53e8ce1a0117d62d187fa051a030..c060eb9b3b19006d1cba689b68f0fe640c1514c1 100644 (file)
@@ -47,7 +47,25 @@ config USB_EHCI_ROOT_HUB_TT
          controller is needed.  It's safe to say "y" even if your
          controller doesn't support this feature.
 
-         This supports the EHCI implementation from TransDimension Inc.
+         This supports the EHCI implementation that's originally
+         from ARC, and has since changed hands a few times.
+
+config USB_EHCI_TT_NEWSCHED
+       bool "Improved Transaction Translator scheduling (EXPERIMENTAL)"
+       depends on USB_EHCI_HCD && EXPERIMENTAL
+       ---help---
+         This changes the periodic scheduling code to fill more of the low
+         and full speed bandwidth available from the Transaction Translator
+         (TT) in USB 2.0 hubs.  Without this, only one transfer will be
+         issued in each microframe, significantly reducing the number of
+         periodic low/fullspeed transfers possible.
+
+         If you have multiple periodic low/fullspeed devices connected to a
+         highspeed USB hub which is connected to a highspeed USB Host
+         Controller, and some of those devices will not work correctly
+         (possibly due to "ENOSPC" or "-28" errors), say Y.
+
+         If unsure, say N.
 
 config USB_ISP116X_HCD
        tristate "ISP116X HCD support"
index 63eadeec132440d4e7b29c531fa483e85d539903..9b4697add3130b4e482bc10483ff774ccc7a57de 100644 (file)
 #include <linux/platform_device.h>
 #include <asm/mach-au1x00/au1000.h>
 
-#ifndef CONFIG_SOC_AU1200
-#error "this Alchemy chip doesn't have EHCI"
-#else                          /* Au1200 */
-
 #define USB_HOST_CONFIG   (USB_MSR_BASE + USB_MSR_MCFG)
 #define USB_MCFG_PFEN     (1<<31)
 #define USB_MCFG_RDCOMB   (1<<30)
@@ -272,6 +268,8 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
        return 0;
 }
 */
+MODULE_ALIAS("au1xxx-ehci");
+/* FIXME use "struct platform_driver" */
 static struct device_driver ehci_hcd_au1xxx_driver = {
        .name = "au1xxx-ehci",
        .bus = &platform_bus_type,
@@ -280,18 +278,3 @@ static struct device_driver ehci_hcd_au1xxx_driver = {
        /*.suspend      = ehci_hcd_au1xxx_drv_suspend, */
        /*.resume       = ehci_hcd_au1xxx_drv_resume, */
 };
-
-static int __init ehci_hcd_au1xxx_init(void)
-{
-       pr_debug(DRIVER_INFO " (Au1xxx)\n");
-
-       return driver_register(&ehci_hcd_au1xxx_driver);
-}
-
-static void __exit ehci_hcd_au1xxx_cleanup(void)
-{
-       driver_unregister(&ehci_hcd_au1xxx_driver);
-}
-
-module_init(ehci_hcd_au1xxx_init);
-module_exit(ehci_hcd_au1xxx_cleanup);
index f985f121a2455fb2d369febeb40327f8cab9306e..a49a689bf4237c619c1d37f971c04d91cebb7268 100644 (file)
@@ -324,43 +324,12 @@ static int ehci_fsl_drv_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver ehci_fsl_dr_driver = {
-       .probe = ehci_fsl_drv_probe,
-       .remove = ehci_fsl_drv_remove,
-       .driver = {
-                  .name = "fsl-usb2-dr",
-                  },
-};
+MODULE_ALIAS("fsl-ehci");
 
-static struct platform_driver ehci_fsl_mph_driver = {
+static struct platform_driver ehci_fsl_driver = {
        .probe = ehci_fsl_drv_probe,
        .remove = ehci_fsl_drv_remove,
        .driver = {
-                  .name = "fsl-usb2-mph",
+                  .name = "fsl-ehci",
                   },
 };
-
-static int __init ehci_fsl_init(void)
-{
-       int retval;
-
-       pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
-                hcd_name,
-                sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
-                sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
-
-       retval = platform_driver_register(&ehci_fsl_dr_driver);
-       if (retval)
-               return retval;
-
-       return platform_driver_register(&ehci_fsl_mph_driver);
-}
-
-static void __exit ehci_fsl_cleanup(void)
-{
-       platform_driver_unregister(&ehci_fsl_mph_driver);
-       platform_driver_unregister(&ehci_fsl_dr_driver);
-}
-
-module_init(ehci_fsl_init);
-module_exit(ehci_fsl_cleanup);
index 79f2d8b9bfb654618768d20abc61c2847d34444e..9b37e508ada329119958d99d6955b7bba2ecbe65 100644 (file)
@@ -889,19 +889,59 @@ MODULE_LICENSE ("GPL");
 
 #ifdef CONFIG_PCI
 #include "ehci-pci.c"
-#define        EHCI_BUS_GLUED
+#define        PCI_DRIVER              ehci_pci_driver
 #endif
 
 #ifdef CONFIG_PPC_83xx
 #include "ehci-fsl.c"
-#define        EHCI_BUS_GLUED
+#define        PLATFORM_DRIVER         ehci_fsl_driver
 #endif
 
-#ifdef CONFIG_SOC_AU1X00
+#ifdef CONFIG_SOC_AU1200
 #include "ehci-au1xxx.c"
-#define        EHCI_BUS_GLUED
+#define        PLATFORM_DRIVER         ehci_hcd_au1xxx_driver
 #endif
 
-#ifndef        EHCI_BUS_GLUED
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #endif
+
+static int __init ehci_hcd_init(void)
+{
+       int retval = 0;
+
+       pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
+                hcd_name,
+                sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
+                sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+
+#ifdef PLATFORM_DRIVER
+       retval = platform_driver_register(&PLATFORM_DRIVER);
+       if (retval < 0)
+               return retval;
+#endif
+
+#ifdef PCI_DRIVER
+       retval = pci_register_driver(&PCI_DRIVER);
+       if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+               platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+       }
+#endif
+
+       return retval;
+}
+module_init(ehci_hcd_init);
+
+static void __exit ehci_hcd_cleanup(void)
+{
+#ifdef PLATFORM_DRIVER
+       platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
+#endif
+}
+module_exit(ehci_hcd_cleanup);
+
index a1bd2bea6debcff9d436495953c2aa1ed01fcbbb..cadffacd945b9d392ab93a96663b7233865ed918 100644 (file)
@@ -76,6 +76,30 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
+        /* ehci_init() causes memory for DMA transfers to be
+         * allocated.  Thus, any vendor-specific workarounds based on
+         * limiting the type of memory used for DMA transfers must
+         * happen before ehci_init() is called. */
+       switch (pdev->vendor) {
+       case PCI_VENDOR_ID_NVIDIA:
+               /* NVidia reports that certain chips don't handle
+                * QH, ITD, or SITD addresses above 2GB.  (But TD,
+                * data buffer, and periodic schedule are normal.)
+                */
+               switch (pdev->device) {
+               case 0x003c:    /* MCP04 */
+               case 0x005b:    /* CK804 */
+               case 0x00d8:    /* CK8 */
+               case 0x00e8:    /* CK8S */
+                       if (pci_set_consistent_dma_mask(pdev,
+                                               DMA_31BIT_MASK) < 0)
+                               ehci_warn(ehci, "can't enable NVidia "
+                                       "workaround for >2GB RAM\n");
+                       break;
+               }
+               break;
+       }
+
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = readl(&ehci->caps->hcs_params);
 
@@ -88,8 +112,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        if (retval)
                return retval;
 
-       /* NOTE:  only the parts below this line are PCI-specific */
-
        switch (pdev->vendor) {
        case PCI_VENDOR_ID_TDI:
                if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
@@ -107,19 +129,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                break;
        case PCI_VENDOR_ID_NVIDIA:
                switch (pdev->device) {
-               /* NVidia reports that certain chips don't handle
-                * QH, ITD, or SITD addresses above 2GB.  (But TD,
-                * data buffer, and periodic schedule are normal.)
-                */
-               case 0x003c:    /* MCP04 */
-               case 0x005b:    /* CK804 */
-               case 0x00d8:    /* CK8 */
-               case 0x00e8:    /* CK8S */
-                       if (pci_set_consistent_dma_mask(pdev,
-                                               DMA_31BIT_MASK) < 0)
-                               ehci_warn(ehci, "can't enable NVidia "
-                                       "workaround for >2GB RAM\n");
-                       break;
                /* Some NForce2 chips have problems with selective suspend;
                 * fixed in newer silicon.
                 */
@@ -370,23 +379,3 @@ static struct pci_driver ehci_pci_driver = {
        .resume =       usb_hcd_pci_resume,
 #endif
 };
-
-static int __init ehci_hcd_pci_init(void)
-{
-       if (usb_disabled())
-               return -ENODEV;
-
-       pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
-               hcd_name,
-               sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
-               sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
-
-       return pci_register_driver(&ehci_pci_driver);
-}
-module_init(ehci_hcd_pci_init);
-
-static void __exit ehci_hcd_pci_cleanup(void)
-{
-       pci_unregister_driver(&ehci_pci_driver);
-}
-module_exit(ehci_hcd_pci_cleanup);
index 5871944e61459cca9cbd9fa85a992186b838c691..4859900bd1351df16b10746b37977dbc217d03cd 100644 (file)
@@ -163,6 +163,190 @@ static int same_tt (struct usb_device *dev1, struct usb_device *dev2)
                return 1;
 }
 
+#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
+
+/* Which uframe does the low/fullspeed transfer start in?
+ *
+ * The parameter is the mask of ssplits in "H-frame" terms
+ * and this returns the transfer start uframe in "B-frame" terms,
+ * which allows both to match, e.g. a ssplit in "H-frame" uframe 0
+ * will cause a transfer in "B-frame" uframe 0.  "B-frames" lag
+ * "H-frames" by 1 uframe.  See the EHCI spec sec 4.5 and figure 4.7.
+ */
+static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __le32 mask)
+{
+       unsigned char smask = QH_SMASK & le32_to_cpu(mask);
+       if (!smask) {
+               ehci_err(ehci, "invalid empty smask!\n");
+               /* uframe 7 can't have bw so this will indicate failure */
+               return 7;
+       }
+       return ffs(smask) - 1;
+}
+
+static const unsigned char
+max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 };
+
+/* carryover low/fullspeed bandwidth that crosses uframe boundries */
+static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])
+{
+       int i;
+       for (i=0; i<7; i++) {
+               if (max_tt_usecs[i] < tt_usecs[i]) {
+                       tt_usecs[i+1] += tt_usecs[i] - max_tt_usecs[i];
+                       tt_usecs[i] = max_tt_usecs[i];
+               }
+       }
+}
+
+/* How many of the tt's periodic downstream 1000 usecs are allocated?
+ *
+ * While this measures the bandwidth in terms of usecs/uframe,
+ * the low/fullspeed bus has no notion of uframes, so any particular
+ * low/fullspeed transfer can "carry over" from one uframe to the next,
+ * since the TT just performs downstream transfers in sequence.
+ *
+ * For example two seperate 100 usec transfers can start in the same uframe,
+ * and the second one would "carry over" 75 usecs into the next uframe.
+ */
+static void
+periodic_tt_usecs (
+       struct ehci_hcd *ehci,
+       struct usb_device *dev,
+       unsigned frame,
+       unsigned short tt_usecs[8]
+)
+{
+       __le32                  *hw_p = &ehci->periodic [frame];
+       union ehci_shadow       *q = &ehci->pshadow [frame];
+       unsigned char           uf;
+
+       memset(tt_usecs, 0, 16);
+
+       while (q->ptr) {
+               switch (Q_NEXT_TYPE(*hw_p)) {
+               case Q_TYPE_ITD:
+                       hw_p = &q->itd->hw_next;
+                       q = &q->itd->itd_next;
+                       continue;
+               case Q_TYPE_QH:
+                       if (same_tt(dev, q->qh->dev)) {
+                               uf = tt_start_uframe(ehci, q->qh->hw_info2);
+                               tt_usecs[uf] += q->qh->tt_usecs;
+                       }
+                       hw_p = &q->qh->hw_next;
+                       q = &q->qh->qh_next;
+                       continue;
+               case Q_TYPE_SITD:
+                       if (same_tt(dev, q->sitd->urb->dev)) {
+                               uf = tt_start_uframe(ehci, q->sitd->hw_uframe);
+                               tt_usecs[uf] += q->sitd->stream->tt_usecs;
+                       }
+                       hw_p = &q->sitd->hw_next;
+                       q = &q->sitd->sitd_next;
+                       continue;
+               // case Q_TYPE_FSTN:
+               default:
+                       ehci_dbg(ehci,
+                                 "ignoring periodic frame %d FSTN\n", frame);
+                       hw_p = &q->fstn->hw_next;
+                       q = &q->fstn->fstn_next;
+               }
+       }
+
+       carryover_tt_bandwidth(tt_usecs);
+
+       if (max_tt_usecs[7] < tt_usecs[7])
+               ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n",
+                       frame, tt_usecs[7] - max_tt_usecs[7]);
+}
+
+/*
+ * Return true if the device's tt's downstream bus is available for a
+ * periodic transfer of the specified length (usecs), starting at the
+ * specified frame/uframe.  Note that (as summarized in section 11.19
+ * of the usb 2.0 spec) TTs can buffer multiple transactions for each
+ * uframe.
+ *
+ * The uframe parameter is when the fullspeed/lowspeed transfer
+ * should be executed in "B-frame" terms, which is the same as the
+ * highspeed ssplit's uframe (which is in "H-frame" terms).  For example
+ * a ssplit in "H-frame" 0 causes a transfer in "B-frame" 0.
+ * See the EHCI spec sec 4.5 and fig 4.7.
+ *
+ * This checks if the full/lowspeed bus, at the specified starting uframe,
+ * has the specified bandwidth available, according to rules listed
+ * in USB 2.0 spec section 11.18.1 fig 11-60.
+ *
+ * This does not check if the transfer would exceed the max ssplit
+ * limit of 16, specified in USB 2.0 spec section 11.18.4 requirement #4,
+ * since proper scheduling limits ssplits to less than 16 per uframe.
+ */
+static int tt_available (
+       struct ehci_hcd         *ehci,
+       unsigned                period,
+       struct usb_device       *dev,
+       unsigned                frame,
+       unsigned                uframe,
+       u16                     usecs
+)
+{
+       if ((period == 0) || (uframe >= 7))     /* error */
+               return 0;
+
+       for (; frame < ehci->periodic_size; frame += period) {
+               unsigned short tt_usecs[8];
+
+               periodic_tt_usecs (ehci, dev, frame, tt_usecs);
+
+               ehci_vdbg(ehci, "tt frame %d check %d usecs start uframe %d in"
+                       " schedule %d/%d/%d/%d/%d/%d/%d/%d\n",
+                       frame, usecs, uframe,
+                       tt_usecs[0], tt_usecs[1], tt_usecs[2], tt_usecs[3],
+                       tt_usecs[4], tt_usecs[5], tt_usecs[6], tt_usecs[7]);
+
+               if (max_tt_usecs[uframe] <= tt_usecs[uframe]) {
+                       ehci_vdbg(ehci, "frame %d uframe %d fully scheduled\n",
+                               frame, uframe);
+                       return 0;
+               }
+
+               /* special case for isoc transfers larger than 125us:
+                * the first and each subsequent fully used uframe
+                * must be empty, so as to not illegally delay
+                * already scheduled transactions
+                */
+               if (125 < usecs) {
+                       int ufs = (usecs / 125) - 1;
+                       int i;
+                       for (i = uframe; i < (uframe + ufs) && i < 8; i++)
+                               if (0 < tt_usecs[i]) {
+                                       ehci_vdbg(ehci,
+                                               "multi-uframe xfer can't fit "
+                                               "in frame %d uframe %d\n",
+                                               frame, i);
+                                       return 0;
+                               }
+               }
+
+               tt_usecs[uframe] += usecs;
+
+               carryover_tt_bandwidth(tt_usecs);
+
+               /* fail if the carryover pushed bw past the last uframe's limit */
+               if (max_tt_usecs[7] < tt_usecs[7]) {
+                       ehci_vdbg(ehci,
+                               "tt unavailable usecs %d frame %d uframe %d\n",
+                               usecs, frame, uframe);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+#else
+
 /* return true iff the device's transaction translator is available
  * for a periodic transfer starting at the specified frame, using
  * all the uframes in the mask.
@@ -237,6 +421,8 @@ static int tt_no_collision (
        return 1;
 }
 
+#endif /* CONFIG_USB_EHCI_TT_NEWSCHED */
+
 /*-------------------------------------------------------------------------*/
 
 static int enable_periodic (struct ehci_hcd *ehci)
@@ -481,7 +667,7 @@ static int check_intr_schedule (
 )
 {
        int             retval = -ENOSPC;
-       u8              mask;
+       u8              mask = 0;
 
        if (qh->c_usecs && uframe >= 6)         /* FSTN territory? */
                goto done;
@@ -494,6 +680,24 @@ static int check_intr_schedule (
                goto done;
        }
 
+#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
+       if (tt_available (ehci, qh->period, qh->dev, frame, uframe,
+                               qh->tt_usecs)) {
+               unsigned i;
+
+               /* TODO : this may need FSTN for SSPLIT in uframe 5. */
+               for (i=uframe+1; i<8 && i<uframe+4; i++)
+                       if (!check_period (ehci, frame, i,
+                                               qh->period, qh->c_usecs))
+                               goto done;
+                       else
+                               mask |= 1 << i;
+
+               retval = 0;
+
+               *c_maskp = cpu_to_le32 (mask << 8);
+       }
+#else
        /* Make sure this tt's buffer is also available for CSPLITs.
         * We pessimize a bit; probably the typical full speed case
         * doesn't need the second CSPLIT.
@@ -514,6 +718,7 @@ static int check_intr_schedule (
                        goto done;
                retval = 0;
        }
+#endif
 done:
        return retval;
 }
@@ -1047,12 +1252,21 @@ sitd_slot_ok (
                frame = uframe >> 3;
                uf = uframe & 7;
 
+#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
+               /* The tt's fullspeed bus bandwidth must be available.
+                * tt_available scheduling guarantees 10+% for control/bulk.
+                */
+               if (!tt_available (ehci, period_uframes << 3,
+                               stream->udev, frame, uf, stream->tt_usecs))
+                       return 0;
+#else
                /* tt must be idle for start(s), any gap, and csplit.
                 * assume scheduling slop leaves 10+% for control/bulk.
                 */
                if (!tt_no_collision (ehci, period_uframes << 3,
                                stream->udev, frame, mask))
                        return 0;
+#endif
 
                /* check starts (OUT uses more than one) */
                max_used = 100 - stream->usecs;
index e99210b7909b3f6507c4ba7e6172cf8a91f34f4f..14386254c87029546d84f8858033958134e31580 100644 (file)
@@ -63,7 +63,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/usb.h>
-#include <linux/usb_isp116x.h>
+#include <linux/usb/isp116x.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
@@ -781,7 +781,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
                if (ep->branch < PERIODIC_SIZE)
                        break;
 
-               ret = ep->branch = balance(isp116x, ep->period, ep->load);
+               ep->branch = ret = balance(isp116x, ep->period, ep->load);
                if (ret < 0)
                        goto fail;
                ret = 0;
index a92343052751c06b57cd99dbc50ed607e17b5eae..6b4bc3f2bd864fd28b3b135118db929735ecf016 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
index 302aa1ec312f55ef21592dd40c4e164ee12d5322..54f554e0f0ade94f5ed961930629676e8a79c0a5 100644 (file)
@@ -27,7 +27,7 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
 
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 
 MODULE_AUTHOR("Botond Botyanszki");
 MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6");
index e1239319655cbcc3b5c6083b2d6e5148463ce04d..6637a0e49978b0b897e671dfd54861db05eb0f89 100644 (file)
@@ -98,6 +98,7 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
        char *out = buf;
        struct uhci_td *td;
        int i, nactive, ninactive;
+       char *ptype;
 
        if (len < 200)
                return 0;
@@ -110,13 +111,15 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
                        (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
 
        switch (usb_pipetype(urbp->urb->pipe)) {
-       case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break;
-       case PIPE_INTERRUPT: out += sprintf(out, "INT"); break;
-       case PIPE_BULK: out += sprintf(out, "BLK"); break;
-       case PIPE_CONTROL: out += sprintf(out, "CTL"); break;
+       case PIPE_ISOCHRONOUS: ptype = "ISO"; break;
+       case PIPE_INTERRUPT: ptype = "INT"; break;
+       case PIPE_BULK: ptype = "BLK"; break;
+       default:
+       case PIPE_CONTROL: ptype = "CTL"; break;
        }
 
-       out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : ""));
+       out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
+       out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
 
        if (urbp->urb->status != -EINPROGRESS)
                out += sprintf(out, " Status=%d", urbp->urb->status);
@@ -124,7 +127,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
 
        i = nactive = ninactive = 0;
        list_for_each_entry(td, &urbp->td_list, list) {
-               if (++i <= 10 || debug > 2) {
+               if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC &&
+                               (++i <= 10 || debug > 2)) {
                        out += sprintf(out, "%*s%d: ", space + 2, "", i);
                        out += uhci_show_td(td, out, len - (out - buf), 0);
                } else {
@@ -147,13 +151,27 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
        char *out = buf;
        int i, nurbs;
        __le32 element = qh_element(qh);
+       char *qtype;
 
        /* Try to make sure there's enough memory */
-       if (len < 80 * 6)
+       if (len < 80 * 7)
                return 0;
 
-       out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
-                       qh, le32_to_cpu(qh->link), le32_to_cpu(element));
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break;
+       case USB_ENDPOINT_XFER_INT: qtype = "INT"; break;
+       case USB_ENDPOINT_XFER_BULK: qtype = "BLK"; break;
+       case USB_ENDPOINT_XFER_CONTROL: qtype = "CTL"; break;
+       default: qtype = "Skel" ; break;
+       }
+
+       out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
+                       space, "", qh, qtype,
+                       le32_to_cpu(qh->link), le32_to_cpu(element));
+       if (qh->type == USB_ENDPOINT_XFER_ISOC)
+               out += sprintf(out, "%*s    period %d frame %x desc [%p]\n",
+                               space, "", qh->period, qh->iso_frame,
+                               qh->iso_packet_desc);
 
        if (element & UHCI_PTR_QH)
                out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
@@ -261,7 +279,8 @@ static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
            default:
                rh_state = "?";                 break;
        }
-       out += sprintf(out, "Root-hub state: %s\n", rh_state);
+       out += sprintf(out, "Root-hub state: %s   FSBR: %d\n",
+                       rh_state, uhci->fsbr_is_on);
        return out - buf;
 }
 
@@ -275,7 +294,7 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
        unsigned short portsc1, portsc2;
 
        /* Try to make sure there's enough memory */
-       if (len < 80 * 6)
+       if (len < 80 * 9)
                return 0;
 
        usbcmd    = inw(io_addr + 0);
@@ -314,6 +333,10 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
        out += sprintf(out, "  sof       =       %02x\n", sof);
        out += uhci_show_sc(1, portsc1, out, len - (out - buf));
        out += uhci_show_sc(2, portsc2, out, len - (out - buf));
+       out += sprintf(out, "Most recent frame: %x (%d)   "
+                       "Last ISO frame: %x (%d)\n",
+                       uhci->frame_number, uhci->frame_number & 1023,
+                       uhci->last_iso_frame, uhci->last_iso_frame & 1023);
 
        return out - buf;
 }
index d225e11f40555983a224353a3e28b039b207a397..7b48567622ef318bc22317c121c752f0a48aa47f 100644 (file)
@@ -13,7 +13,7 @@
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
  *
  * Intel documents this fairly well, and as far as I know there
  * are no royalties or anything like that, but even so there are
@@ -31,7 +31,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/unistd.h>
 #include <linux/interrupt.h>
@@ -88,15 +87,6 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
 static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 
-/* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT   msecs_to_jiffies(50)
-#define FSBR_DELAY     msecs_to_jiffies(50)
-
-/* When we timeout an idle transfer for FSBR, we'll switch it over to */
-/* depth first traversal. We'll do it in groups of this number of TDs */
-/* to make sure it doesn't hog all of the bandwidth */
-#define DEPTH_INTERVAL 5
-
 #include "uhci-debug.c"
 #include "uhci-q.c"
 #include "uhci-hub.c"
@@ -120,22 +110,29 @@ static void finish_reset(struct uhci_hcd *uhci)
        uhci->is_stopped = UHCI_IS_STOPPED;
        uhci_to_hcd(uhci)->state = HC_STATE_HALT;
        uhci_to_hcd(uhci)->poll_rh = 0;
+
+       uhci->dead = 0;         /* Full reset resurrects the controller */
 }
 
 /*
  * Last rites for a defunct/nonfunctional controller
  * or one we don't want to use any more.
  */
-static void hc_died(struct uhci_hcd *uhci)
+static void uhci_hc_died(struct uhci_hcd *uhci)
 {
+       uhci_get_current_frame_number(uhci);
        uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
        finish_reset(uhci);
-       uhci->hc_inaccessible = 1;
+       uhci->dead = 1;
+
+       /* The current frame may already be partway finished */
+       ++uhci->frame_number;
 }
 
 /*
- * Initialize a controller that was newly discovered or has just been
- * resumed.  In either case we can't be sure of its previous state.
+ * Initialize a controller that was newly discovered or has lost power
+ * or otherwise been reset while it was suspended.  In none of these cases
+ * can we be sure of its previous state.
  */
 static void check_and_reset_hc(struct uhci_hcd *uhci)
 {
@@ -155,7 +152,8 @@ static void configure_hc(struct uhci_hcd *uhci)
        outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
 
        /* Set the current frame number */
-       outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
+       outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
+                       uhci->io_addr + USBFRNUM);
 
        /* Mark controller as not halted before we enable interrupts */
        uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
@@ -207,7 +205,8 @@ __acquires(uhci->lock)
        int int_enable;
 
        auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
-       dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+       dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
+                       "%s%s\n", __FUNCTION__,
                        (auto_stop ? " (auto-stop)" : ""));
 
        /* If we get a suspend request when we're already auto-stopped
@@ -241,27 +240,27 @@ __acquires(uhci->lock)
                spin_unlock_irq(&uhci->lock);
                msleep(1);
                spin_lock_irq(&uhci->lock);
-               if (uhci->hc_inaccessible)      /* Died */
+               if (uhci->dead)
                        return;
        }
        if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
-               dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
+               dev_warn(&uhci_to_hcd(uhci)->self.root_hub->dev,
+                       "Controller not stopped yet!\n");
 
        uhci_get_current_frame_number(uhci);
-       smp_wmb();
 
        uhci->rh_state = new_state;
        uhci->is_stopped = UHCI_IS_STOPPED;
        uhci_to_hcd(uhci)->poll_rh = !int_enable;
 
        uhci_scan_schedule(uhci, NULL);
+       uhci_fsbr_off(uhci);
 }
 
 static void start_rh(struct uhci_hcd *uhci)
 {
        uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
        uhci->is_stopped = 0;
-       smp_wmb();
 
        /* Mark it configured and running with a 64-byte max packet.
         * All interrupts are enabled, even though RESUME won't do anything.
@@ -278,7 +277,8 @@ static void wakeup_rh(struct uhci_hcd *uhci)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 {
-       dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+       dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
+                       "%s%s\n", __FUNCTION__,
                        uhci->rh_state == UHCI_RH_AUTO_STOPPED ?
                                " (auto-start)" : "");
 
@@ -293,7 +293,7 @@ __acquires(uhci->lock)
                spin_unlock_irq(&uhci->lock);
                msleep(20);
                spin_lock_irq(&uhci->lock);
-               if (uhci->hc_inaccessible)      /* Died */
+               if (uhci->dead)
                        return;
 
                /* End Global Resume and wait for EOP to be sent */
@@ -345,7 +345,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
                                                        errbuf, ERRBUF_LEN);
                                        lprintk(errbuf);
                                }
-                               hc_died(uhci);
+                               uhci_hc_died(uhci);
 
                                /* Force a callback in case there are
                                 * pending unlinks */
@@ -368,12 +368,21 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 
 /*
  * Store the current frame number in uhci->frame_number if the controller
- * is runnning
+ * is runnning.  Expand from 11 bits (of which we use only 10) to a
+ * full-sized integer.
+ *
+ * Like many other parts of the driver, this code relies on being polled
+ * more than once per second as long as the controller is running.
  */
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
 {
-       if (!uhci->is_stopped)
-               uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
+       if (!uhci->is_stopped) {
+               unsigned delta;
+
+               delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) &
+                               (UHCI_NUMFRAMES - 1);
+               uhci->frame_number += delta;
+       }
 }
 
 /*
@@ -407,7 +416,7 @@ static void release_uhci(struct uhci_hcd *uhci)
                        uhci->frame, uhci->frame_dma_handle);
 }
 
-static int uhci_reset(struct usb_hcd *hcd)
+static int uhci_init(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned io_size = (unsigned) hcd->rsrc_len;
@@ -459,7 +468,7 @@ static void uhci_shutdown(struct pci_dev *pdev)
 {
        struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev);
 
-       hc_died(hcd_to_uhci(hcd));
+       uhci_hc_died(hcd_to_uhci(hcd));
 }
 
 /*
@@ -487,14 +496,10 @@ static int uhci_start(struct usb_hcd *hcd)
 
        hcd->uses_new_polling = 1;
 
-       uhci->fsbr = 0;
-       uhci->fsbrtimeout = 0;
-
        spin_lock_init(&uhci->lock);
-
-       INIT_LIST_HEAD(&uhci->td_remove_list);
+       setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout,
+                       (unsigned long) uhci);
        INIT_LIST_HEAD(&uhci->idle_qh_list);
-
        init_waitqueue_head(&uhci->waitqh);
 
        if (DEBUG_CONFIGURED) {
@@ -665,11 +670,12 @@ static void uhci_stop(struct usb_hcd *hcd)
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
        spin_lock_irq(&uhci->lock);
-       if (!uhci->hc_inaccessible)
-               hc_died(uhci);
+       if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead)
+               uhci_hc_died(uhci);
        uhci_scan_schedule(uhci, NULL);
        spin_unlock_irq(&uhci->lock);
 
+       del_timer_sync(&uhci->fsbr_timer);
        release_uhci(uhci);
 }
 
@@ -677,12 +683,15 @@ static void uhci_stop(struct usb_hcd *hcd)
 static int uhci_rh_suspend(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       int rc = 0;
 
        spin_lock_irq(&uhci->lock);
-       if (!uhci->hc_inaccessible)             /* Not dead */
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+               rc = -ESHUTDOWN;
+       else if (!uhci->dead)
                suspend_rh(uhci, UHCI_RH_SUSPENDED);
        spin_unlock_irq(&uhci->lock);
-       return 0;
+       return rc;
 }
 
 static int uhci_rh_resume(struct usb_hcd *hcd)
@@ -691,13 +700,10 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
        int rc = 0;
 
        spin_lock_irq(&uhci->lock);
-       if (uhci->hc_inaccessible) {
-               if (uhci->rh_state == UHCI_RH_SUSPENDED) {
-                       dev_warn(uhci_dev(uhci), "HC isn't running!\n");
-                       rc = -ENODEV;
-               }
-               /* Otherwise the HC is dead */
-       } else
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+               dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n");
+               rc = -ESHUTDOWN;
+       } else if (!uhci->dead)
                wakeup_rh(uhci);
        spin_unlock_irq(&uhci->lock);
        return rc;
@@ -711,8 +717,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
        dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
 
        spin_lock_irq(&uhci->lock);
-       if (uhci->hc_inaccessible)      /* Dead or already suspended */
-               goto done;
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
+               goto done_okay;         /* Already suspended or dead */
 
        if (uhci->rh_state > UHCI_RH_SUSPENDED) {
                dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
@@ -725,12 +731,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
         */
        pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
        mb();
-       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-       uhci->hc_inaccessible = 1;
        hcd->poll_rh = 0;
 
        /* FIXME: Enable non-PME# remote wakeup? */
 
+done_okay:
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 done:
        spin_unlock_irq(&uhci->lock);
        return rc;
@@ -743,24 +749,22 @@ static int uhci_resume(struct usb_hcd *hcd)
        dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
 
        /* Since we aren't in D3 any more, it's safe to set this flag
-        * even if the controller was dead.  It might not even be dead
-        * any more, if the firmware or quirks code has reset it.
+        * even if the controller was dead.
         */
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        mb();
 
-       if (uhci->rh_state == UHCI_RH_RESET)    /* Dead */
-               return 0;
        spin_lock_irq(&uhci->lock);
 
        /* FIXME: Disable non-PME# remote wakeup? */
 
-       uhci->hc_inaccessible = 0;
-
-       /* The BIOS may have changed the controller settings during a
-        * system wakeup.  Check it and reconfigure to avoid problems.
+       /* The firmware or a boot kernel may have changed the controller
+        * settings during a system wakeup.  Check it and reconfigure
+        * to avoid problems.
         */
        check_and_reset_hc(uhci);
+
+       /* If the controller was dead before, it's back alive now */
        configure_hc(uhci);
 
        if (uhci->rh_state == UHCI_RH_RESET) {
@@ -810,18 +814,15 @@ done:
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       unsigned long flags;
-       int is_stopped;
-       int frame_number;
+       unsigned frame_number;
+       unsigned delta;
 
        /* Minimize latency by avoiding the spinlock */
-       local_irq_save(flags);
-       is_stopped = uhci->is_stopped;
-       smp_rmb();
-       frame_number = (is_stopped ? uhci->frame_number :
-                       inw(uhci->io_addr + USBFRNUM));
-       local_irq_restore(flags);
-       return frame_number;
+       frame_number = uhci->frame_number;
+       barrier();
+       delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) &
+                       (UHCI_NUMFRAMES - 1);
+       return frame_number + delta;
 }
 
 static const char hcd_name[] = "uhci_hcd";
@@ -836,7 +837,7 @@ static const struct hc_driver uhci_driver = {
        .flags =                HCD_USB11,
 
        /* Basic lifecycle operations */
-       .reset =                uhci_reset,
+       .reset =                uhci_init,
        .start =                uhci_start,
 #ifdef CONFIG_PM
        .suspend =              uhci_suspend,
index d5c8f4d928236ba58ef62bd448c506c078f7f9e4..108e3de2dc26f55acd49770a718b55dd42f55cc1 100644 (file)
 #define CAN_SCHEDULE_FRAMES    1000    /* how far in the future frames
                                         * can be scheduled */
 
+/* When no queues need Full-Speed Bandwidth Reclamation,
+ * delay this long before turning FSBR off */
+#define FSBR_OFF_DELAY         msecs_to_jiffies(10)
+
+/* If a queue hasn't advanced after this much time, assume it is stuck */
+#define QH_WAIT_TIMEOUT                msecs_to_jiffies(200)
+
 
 /*
  *     Queue Headers
@@ -121,21 +128,31 @@ struct uhci_qh {
        __le32 element;                 /* Queue element (TD) pointer */
 
        /* Software fields */
-       dma_addr_t dma_handle;
-
        struct list_head node;          /* Node in the list of QHs */
        struct usb_host_endpoint *hep;  /* Endpoint information */
        struct usb_device *udev;
        struct list_head queue;         /* Queue of urbps for this QH */
        struct uhci_qh *skel;           /* Skeleton for this QH */
        struct uhci_td *dummy_td;       /* Dummy TD to end the queue */
+       struct uhci_td *post_td;        /* Last TD completed */
 
+       struct usb_iso_packet_descriptor *iso_packet_desc;
+                                       /* Next urb->iso_frame_desc entry */
+       unsigned long advance_jiffies;  /* Time of last queue advance */
        unsigned int unlink_frame;      /* When the QH was unlinked */
+       unsigned int period;            /* For Interrupt and Isochronous QHs */
+       unsigned int iso_frame;         /* Frame # for iso_packet_desc */
+       int iso_status;                 /* Status for Isochronous URBs */
+
        int state;                      /* QH_STATE_xxx; see above */
+       int type;                       /* Queue type (control, bulk, etc) */
+
+       dma_addr_t dma_handle;
 
        unsigned int initial_toggle:1;  /* Endpoint's current toggle value */
        unsigned int needs_fixup:1;     /* Must fix the TD toggle values */
-       unsigned int is_stopped:1;      /* Queue was stopped by an error */
+       unsigned int is_stopped:1;      /* Queue was stopped by error/unlink */
+       unsigned int wait_expired:1;    /* QH_WAIT_TIMEOUT has expired */
 } __attribute__((aligned(16)));
 
 /*
@@ -226,7 +243,6 @@ struct uhci_td {
        dma_addr_t dma_handle;
 
        struct list_head list;
-       struct list_head remove_list;
 
        int frame;                      /* for iso: what frame? */
        struct list_head fl_list;
@@ -305,38 +321,8 @@ static inline u32 td_status(struct uhci_td *td) {
 #define skel_bulk_qh           skelqh[12]
 #define skel_term_qh           skelqh[13]
 
-/*
- * Search tree for determining where <interval> fits in the skelqh[]
- * skeleton.
- *
- * An interrupt request should be placed into the slowest skelqh[]
- * which meets the interval/period/frequency requirement.
- * An interrupt request is allowed to be faster than <interval> but not slower.
- *
- * For a given <interval>, this function returns the appropriate/matching
- * skelqh[] index value.
- */
-static inline int __interval_to_skel(int interval)
-{
-       if (interval < 16) {
-               if (interval < 4) {
-                       if (interval < 2)
-                               return 9;       /* int1 for 0-1 ms */
-                       return 8;               /* int2 for 2-3 ms */
-               }
-               if (interval < 8)
-                       return 7;               /* int4 for 4-7 ms */
-               return 6;                       /* int8 for 8-15 ms */
-       }
-       if (interval < 64) {
-               if (interval < 32)
-                       return 5;               /* int16 for 16-31 ms */
-               return 4;                       /* int32 for 32-63 ms */
-       }
-       if (interval < 128)
-               return 3;                       /* int64 for 64-127 ms */
-       return 2;                               /* int128 for 128-255 ms (Max.) */
-}
+/* Find the skelqh entry corresponding to an interval exponent */
+#define UHCI_SKEL_INDEX(exponent)      (9 - exponent)
 
 
 /*
@@ -396,32 +382,32 @@ struct uhci_hcd {
        __le32 *frame;
        void **frame_cpu;               /* CPU's frame list */
 
-       int fsbr;                       /* Full-speed bandwidth reclamation */
-       unsigned long fsbrtimeout;      /* FSBR delay */
-
        enum uhci_rh_state rh_state;
        unsigned long auto_stop_time;           /* When to AUTO_STOP */
 
        unsigned int frame_number;              /* As of last check */
        unsigned int is_stopped;
 #define UHCI_IS_STOPPED                9999            /* Larger than a frame # */
+       unsigned int last_iso_frame;            /* Frame of last scan */
+       unsigned int cur_iso_frame;             /* Frame for current scan */
 
        unsigned int scan_in_progress:1;        /* Schedule scan is running */
        unsigned int need_rescan:1;             /* Redo the schedule scan */
-       unsigned int hc_inaccessible:1;         /* HC is suspended or dead */
+       unsigned int dead:1;                    /* Controller has died */
        unsigned int working_RD:1;              /* Suspended root hub doesn't
                                                   need to be polled */
        unsigned int is_initialized:1;          /* Data structure is usable */
+       unsigned int fsbr_is_on:1;              /* FSBR is turned on */
+       unsigned int fsbr_is_wanted:1;          /* Does any URB want FSBR? */
+       unsigned int fsbr_expiring:1;           /* FSBR is timing out */
+
+       struct timer_list fsbr_timer;           /* For turning off FBSR */
 
        /* Support for port suspend/resume/reset */
        unsigned long port_c_suspend;           /* Bit-arrays of ports */
        unsigned long resuming_ports;
        unsigned long ports_timeout;            /* Time to stop signalling */
 
-       /* List of TDs that are done, but waiting to be freed (race) */
-       struct list_head td_remove_list;
-       unsigned int td_remove_age;             /* Age in frames */
-
        struct list_head idle_qh_list;          /* Where the idle QHs live */
 
        int rh_numports;                        /* Number of root-hub ports */
@@ -442,6 +428,9 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
 
 #define uhci_dev(u)    (uhci_to_hcd(u)->self.controller)
 
+/* Utility macro for comparing frame numbers */
+#define uhci_frame_before_eq(f1, f2)   (0 <= (int) ((f2) - (f1)))
+
 
 /*
  *     Private per-URB data
@@ -454,9 +443,7 @@ struct urb_priv {
        struct uhci_qh *qh;             /* QH for this URB */
        struct list_head td_list;
 
-       unsigned fsbr : 1;              /* URB turned on FSBR */
-       unsigned short_transfer : 1;    /* URB got a short transfer, no
-                                        * need to rescan */
+       unsigned fsbr:1;                /* URB wants FSBR */
 };
 
 
index c8451d9578f16ebd96df6501f058efbca031f24a..c545ef92fe29ad130a7b1de0088a945e4bd29751 100644 (file)
@@ -171,9 +171,8 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
        spin_lock_irqsave(&uhci->lock, flags);
 
        uhci_scan_schedule(uhci, NULL);
-       if (uhci->hc_inaccessible)
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
                goto done;
-       check_fsbr(uhci);
        uhci_check_ports(uhci);
 
        status = get_hub_status_data(uhci, buf);
@@ -228,7 +227,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        u16 wPortChange, wPortStatus;
        unsigned long flags;
 
-       if (uhci->hc_inaccessible)
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
                return -ETIMEDOUT;
 
        spin_lock_irqsave(&uhci->lock, flags);
index a06d84c19e13c944f99ffa604cb15034c06ffd42..c9d72ac0a1d775872ed78ed733980e40244749a0 100644 (file)
  * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
  *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
  * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
  */
 
-static void uhci_free_pending_tds(struct uhci_hcd *uhci);
 
 /*
  * Technically, updating td->status here is a race, but it's not really a
@@ -38,6 +37,60 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
        uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
 }
 
+
+/*
+ * Full-Speed Bandwidth Reclamation (FSBR).
+ * We turn on FSBR whenever a queue that wants it is advancing,
+ * and leave it on for a short time thereafter.
+ */
+static void uhci_fsbr_on(struct uhci_hcd *uhci)
+{
+       uhci->fsbr_is_on = 1;
+       uhci->skel_term_qh->link = cpu_to_le32(
+                       uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+}
+
+static void uhci_fsbr_off(struct uhci_hcd *uhci)
+{
+       uhci->fsbr_is_on = 0;
+       uhci->skel_term_qh->link = UHCI_PTR_TERM;
+}
+
+static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
+{
+       struct urb_priv *urbp = urb->hcpriv;
+
+       if (!(urb->transfer_flags & URB_NO_FSBR))
+               urbp->fsbr = 1;
+}
+
+static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp)
+{
+       if (urbp->fsbr) {
+               uhci->fsbr_is_wanted = 1;
+               if (!uhci->fsbr_is_on)
+                       uhci_fsbr_on(uhci);
+               else if (uhci->fsbr_expiring) {
+                       uhci->fsbr_expiring = 0;
+                       del_timer(&uhci->fsbr_timer);
+               }
+       }
+}
+
+static void uhci_fsbr_timeout(unsigned long _uhci)
+{
+       struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
+       unsigned long flags;
+
+       spin_lock_irqsave(&uhci->lock, flags);
+       if (uhci->fsbr_expiring) {
+               uhci->fsbr_expiring = 0;
+               uhci_fsbr_off(uhci);
+       }
+       spin_unlock_irqrestore(&uhci->lock, flags);
+}
+
+
 static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
 {
        dma_addr_t dma_handle;
@@ -51,7 +104,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
        td->frame = -1;
 
        INIT_LIST_HEAD(&td->list);
-       INIT_LIST_HEAD(&td->remove_list);
        INIT_LIST_HEAD(&td->fl_list);
 
        return td;
@@ -61,8 +113,6 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
 {
        if (!list_empty(&td->list))
                dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
-       if (!list_empty(&td->remove_list))
-               dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td);
        if (!list_empty(&td->fl_list))
                dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
 
@@ -77,6 +127,16 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status,
        td->buffer = cpu_to_le32(buffer);
 }
 
+static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp)
+{
+       list_add_tail(&td->list, &urbp->td_list);
+}
+
+static void uhci_remove_td_from_urbp(struct uhci_td *td)
+{
+       list_del_init(&td->list);
+}
+
 /*
  * We insert Isochronous URBs directly into the frame list at the beginning
  */
@@ -138,6 +198,24 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
        td->frame = -1;
 }
 
+static inline void uhci_remove_tds_from_frame(struct uhci_hcd *uhci,
+               unsigned int framenum)
+{
+       struct uhci_td *ftd, *ltd;
+
+       framenum &= (UHCI_NUMFRAMES - 1);
+
+       ftd = uhci->frame_cpu[framenum];
+       if (ftd) {
+               ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
+               uhci->frame[framenum] = ltd->link;
+               uhci->frame_cpu[framenum] = NULL;
+
+               while (!list_empty(&ftd->fl_list))
+                       list_del_init(ftd->fl_list.prev);
+       }
+}
+
 /*
  * Remove all the TDs for an Isochronous URB from the frame list
  */
@@ -148,7 +226,6 @@ static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
 
        list_for_each_entry(td, &urbp->td_list, list)
                uhci_remove_td_from_frame_list(uhci, td);
-       wmb();
 }
 
 static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
@@ -161,6 +238,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
        if (!qh)
                return NULL;
 
+       memset(qh, 0, sizeof(*qh));
        qh->dma_handle = dma_handle;
 
        qh->element = UHCI_PTR_TERM;
@@ -179,10 +257,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
                qh->hep = hep;
                qh->udev = udev;
                hep->hcpriv = qh;
+               qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
 
        } else {                /* Skeleton QH */
                qh->state = QH_STATE_ACTIVE;
-               qh->udev = NULL;
+               qh->type = -1;
        }
        return qh;
 }
@@ -202,35 +281,64 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 }
 
 /*
- * When the currently executing URB is dequeued, save its current toggle value
+ * When a queue is stopped and a dequeued URB is given back, adjust
+ * the previous TD link (if the URB isn't first on the queue) or
+ * save its toggle value (if it is first and is currently executing).
+ *
+ * Returns 0 if the URB should not yet be given back, 1 otherwise.
  */
-static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb)
+static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
+               struct urb *urb)
 {
-       struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+       struct urb_priv *urbp = urb->hcpriv;
        struct uhci_td *td;
+       int ret = 1;
+
+       /* Isochronous pipes don't use toggles and their TD link pointers
+        * get adjusted during uhci_urb_dequeue().  But since their queues
+        * cannot truly be stopped, we have to watch out for dequeues
+        * occurring after the nominal unlink frame. */
+       if (qh->type == USB_ENDPOINT_XFER_ISOC) {
+               ret = (uhci->frame_number + uhci->is_stopped !=
+                               qh->unlink_frame);
+               goto done;
+       }
+
+       /* If the URB isn't first on its queue, adjust the link pointer
+        * of the last TD in the previous URB.  The toggle doesn't need
+        * to be saved since this URB can't be executing yet. */
+       if (qh->queue.next != &urbp->node) {
+               struct urb_priv *purbp;
+               struct uhci_td *ptd;
+
+               purbp = list_entry(urbp->node.prev, struct urb_priv, node);
+               WARN_ON(list_empty(&purbp->td_list));
+               ptd = list_entry(purbp->td_list.prev, struct uhci_td,
+                               list);
+               td = list_entry(urbp->td_list.prev, struct uhci_td,
+                               list);
+               ptd->link = td->link;
+               goto done;
+       }
 
        /* If the QH element pointer is UHCI_PTR_TERM then then currently
         * executing URB has already been unlinked, so this one isn't it. */
-       if (qh_element(qh) == UHCI_PTR_TERM ||
-                               qh->queue.next != &urbp->node)
-               return;
+       if (qh_element(qh) == UHCI_PTR_TERM)
+               goto done;
        qh->element = UHCI_PTR_TERM;
 
-       /* Only bulk and interrupt pipes have to worry about toggles */
-       if (!(usb_pipetype(urb->pipe) == PIPE_BULK ||
-                       usb_pipetype(urb->pipe) == PIPE_INTERRUPT))
-               return;
+       /* Control pipes have to worry about toggles */
+       if (qh->type == USB_ENDPOINT_XFER_CONTROL)
+               goto done;
 
-       /* Find the first active TD; that's the device's toggle state */
-       list_for_each_entry(td, &urbp->td_list, list) {
-               if (td_status(td) & TD_CTRL_ACTIVE) {
-                       qh->needs_fixup = 1;
-                       qh->initial_toggle = uhci_toggle(td_token(td));
-                       return;
-               }
-       }
+       /* Save the next toggle value */
+       WARN_ON(list_empty(&urbp->td_list));
+       td = list_entry(urbp->td_list.next, struct uhci_td, list);
+       qh->needs_fixup = 1;
+       qh->initial_toggle = uhci_toggle(td_token(td));
 
-       WARN_ON(1);
+done:
+       return ret;
 }
 
 /*
@@ -305,6 +413,10 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
                qh->element = cpu_to_le32(td->dma_handle);
        }
 
+       /* Treat the queue as if it has just advanced */
+       qh->wait_expired = 0;
+       qh->advance_jiffies = jiffies;
+
        if (qh->state == QH_STATE_ACTIVE)
                return;
        qh->state = QH_STATE_ACTIVE;
@@ -370,6 +482,12 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
        list_move(&qh->node, &uhci->idle_qh_list);
        qh->state = QH_STATE_IDLE;
 
+       /* Now that the QH is idle, its post_td isn't being used */
+       if (qh->post_td) {
+               uhci_free_td(uhci, qh->post_td);
+               qh->post_td = NULL;
+       }
+
        /* If anyone is waiting for a QH to become idle, wake them up */
        if (uhci->num_waiting)
                wake_up_all(&uhci->waitqh);
@@ -395,21 +513,6 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
        return urbp;
 }
 
-static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-       list_add_tail(&td->list, &urbp->td_list);
-}
-
-static void uhci_remove_td_from_urb(struct uhci_td *td)
-{
-       if (list_empty(&td->list))
-               return;
-
-       list_del_init(&td->list);
-}
-
 static void uhci_free_urb_priv(struct uhci_hcd *uhci,
                struct urb_priv *urbp)
 {
@@ -419,48 +522,15 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
                dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
                                urbp->urb);
 
-       uhci_get_current_frame_number(uhci);
-       if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
-               uhci_free_pending_tds(uhci);
-               uhci->td_remove_age = uhci->frame_number;
-       }
-
-       /* Check to see if the remove list is empty. Set the IOC bit */
-       /* to force an interrupt so we can remove the TDs. */
-       if (list_empty(&uhci->td_remove_list))
-               uhci_set_next_interrupt(uhci);
-
        list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
-               uhci_remove_td_from_urb(td);
-               list_add(&td->remove_list, &uhci->td_remove_list);
+               uhci_remove_td_from_urbp(td);
+               uhci_free_td(uhci, td);
        }
 
        urbp->urb->hcpriv = NULL;
        kmem_cache_free(uhci_up_cachep, urbp);
 }
 
-static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-       if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
-               urbp->fsbr = 1;
-               if (!uhci->fsbr++ && !uhci->fsbrtimeout)
-                       uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
-       }
-}
-
-static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-       if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
-               urbp->fsbr = 0;
-               if (!--uhci->fsbr)
-                       uhci->fsbrtimeout = jiffies + FSBR_DELAY;
-       }
-}
-
 /*
  * Map status to standard result codes
  *
@@ -487,7 +557,6 @@ static int uhci_map_status(int status, int dir_out)
                return -ENOSR;
        if (status & TD_CTRL_STALLED)                   /* Stalled */
                return -EPIPE;
-       WARN_ON(status & TD_CTRL_ACTIVE);               /* Active */
        return 0;
 }
 
@@ -503,6 +572,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
        int len = urb->transfer_buffer_length;
        dma_addr_t data = urb->transfer_dma;
        __le32 *plink;
+       struct urb_priv *urbp = urb->hcpriv;
 
        /* The "pipe" thing contains the destination in bits 8--18 */
        destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -516,7 +586,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
         * Build the TD for the control request setup packet
         */
        td = qh->dummy_td;
-       uhci_add_td_to_urb(urb, td);
+       uhci_add_td_to_urbp(td, urbp);
        uhci_fill_td(td, status, destination | uhci_explen(8),
                        urb->setup_dma);
        plink = &td->link;
@@ -548,7 +618,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
                /* Alternate Data0/1 (start with Data1) */
                destination ^= TD_TOKEN_TOGGLE;
        
-               uhci_add_td_to_urb(urb, td);
+               uhci_add_td_to_urbp(td, urbp);
                uhci_fill_td(td, status, destination | uhci_explen(pktsze),
                                data);
                plink = &td->link;
@@ -579,7 +649,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
 
        status &= ~TD_CTRL_SPD;
 
-       uhci_add_td_to_urb(urb, td);
+       uhci_add_td_to_urbp(td, urbp);
        uhci_fill_td(td, status | TD_CTRL_IOC,
                        destination | uhci_explen(0), 0);
        plink = &td->link;
@@ -606,144 +676,18 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
                qh->skel = uhci->skel_ls_control_qh;
        else {
                qh->skel = uhci->skel_fs_control_qh;
-               uhci_inc_fsbr(uhci, urb);
+               uhci_add_fsbr(uhci, urb);
        }
+
+       urb->actual_length = -8;        /* Account for the SETUP packet */
        return 0;
 
 nomem:
        /* Remove the dummy TD from the td_list so it doesn't get freed */
-       uhci_remove_td_from_urb(qh->dummy_td);
+       uhci_remove_td_from_urbp(qh->dummy_td);
        return -ENOMEM;
 }
 
-/*
- * If control-IN transfer was short, the status packet wasn't sent.
- * This routine changes the element pointer in the QH to point at the
- * status TD.  It's safe to do this even while the QH is live, because
- * the hardware only updates the element pointer following a successful
- * transfer.  The inactive TD for the short packet won't cause an update,
- * so the pointer won't get overwritten.  The next time the controller
- * sees this QH, it will send the status packet.
- */
-static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       struct uhci_td *td;
-
-       urbp->short_transfer = 1;
-
-       td = list_entry(urbp->td_list.prev, struct uhci_td, list);
-       urbp->qh->element = cpu_to_le32(td->dma_handle);
-
-       return -EINPROGRESS;
-}
-
-
-static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct list_head *tmp, *head;
-       struct urb_priv *urbp = urb->hcpriv;
-       struct uhci_td *td;
-       unsigned int status;
-       int ret = 0;
-
-       head = &urbp->td_list;
-       if (urbp->short_transfer) {
-               tmp = head->prev;
-               goto status_stage;
-       }
-
-       urb->actual_length = 0;
-
-       tmp = head->next;
-       td = list_entry(tmp, struct uhci_td, list);
-
-       /* The first TD is the SETUP stage, check the status, but skip */
-       /*  the count */
-       status = uhci_status_bits(td_status(td));
-       if (status & TD_CTRL_ACTIVE)
-               return -EINPROGRESS;
-
-       if (status)
-               goto td_error;
-
-       /* The rest of the TDs (but the last) are data */
-       tmp = tmp->next;
-       while (tmp != head && tmp->next != head) {
-               unsigned int ctrlstat;
-
-               td = list_entry(tmp, struct uhci_td, list);
-               tmp = tmp->next;
-
-               ctrlstat = td_status(td);
-               status = uhci_status_bits(ctrlstat);
-               if (status & TD_CTRL_ACTIVE)
-                       return -EINPROGRESS;
-
-               urb->actual_length += uhci_actual_length(ctrlstat);
-
-               if (status)
-                       goto td_error;
-
-               /* Check to see if we received a short packet */
-               if (uhci_actual_length(ctrlstat) <
-                               uhci_expected_length(td_token(td))) {
-                       if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-                               ret = -EREMOTEIO;
-                               goto err;
-                       }
-
-                       return usb_control_retrigger_status(uhci, urb);
-               }
-       }
-
-status_stage:
-       td = list_entry(tmp, struct uhci_td, list);
-
-       /* Control status stage */
-       status = td_status(td);
-
-#ifdef I_HAVE_BUGGY_APC_BACKUPS
-       /* APC BackUPS Pro kludge */
-       /* It tries to send all of the descriptor instead of the amount */
-       /*  we requested */
-       if (status & TD_CTRL_IOC &&     /* IOC is masked out by uhci_status_bits */
-           status & TD_CTRL_ACTIVE &&
-           status & TD_CTRL_NAK)
-               return 0;
-#endif
-
-       status = uhci_status_bits(status);
-       if (status & TD_CTRL_ACTIVE)
-               return -EINPROGRESS;
-
-       if (status)
-               goto td_error;
-
-       return 0;
-
-td_error:
-       ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-
-err:
-       if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-               /* Some debugging code */
-               dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
-                               __FUNCTION__, status);
-
-               if (errbuf) {
-                       /* Print the chain for debugging purposes */
-                       uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-                       lprintk(errbuf);
-               }
-       }
-
-       /* Note that the queue has stopped */
-       urbp->qh->element = UHCI_PTR_TERM;
-       urbp->qh->is_stopped = 1;
-       return ret;
-}
-
 /*
  * Common submit for bulk and interrupt
  */
@@ -756,6 +700,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        int len = urb->transfer_buffer_length;
        dma_addr_t data = urb->transfer_dma;
        __le32 *plink;
+       struct urb_priv *urbp = urb->hcpriv;
        unsigned int toggle;
 
        if (len < 0)
@@ -793,7 +738,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
                                goto nomem;
                        *plink = cpu_to_le32(td->dma_handle);
                }
-               uhci_add_td_to_urb(urb, td);
+               uhci_add_td_to_urbp(td, urbp);
                uhci_fill_td(td, status,
                                destination | uhci_explen(pktsze) |
                                        (toggle << TD_TOKEN_TOGGLE_SHIFT),
@@ -821,7 +766,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
                        goto nomem;
                *plink = cpu_to_le32(td->dma_handle);
 
-               uhci_add_td_to_urb(urb, td);
+               uhci_add_td_to_urbp(td, urbp);
                uhci_fill_td(td, status,
                                destination | uhci_explen(0) |
                                        (toggle << TD_TOKEN_TOGGLE_SHIFT),
@@ -851,6 +796,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        wmb();
        qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
        qh->dummy_td = td;
+       qh->period = urb->interval;
 
        usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                        usb_pipeout(urb->pipe), toggle);
@@ -858,90 +804,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
 
 nomem:
        /* Remove the dummy TD from the td_list so it doesn't get freed */
-       uhci_remove_td_from_urb(qh->dummy_td);
+       uhci_remove_td_from_urbp(qh->dummy_td);
        return -ENOMEM;
 }
 
-/*
- * Common result for bulk and interrupt
- */
-static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *urbp = urb->hcpriv;
-       struct uhci_td *td;
-       unsigned int status = 0;
-       int ret = 0;
-
-       urb->actual_length = 0;
-
-       list_for_each_entry(td, &urbp->td_list, list) {
-               unsigned int ctrlstat = td_status(td);
-
-               status = uhci_status_bits(ctrlstat);
-               if (status & TD_CTRL_ACTIVE)
-                       return -EINPROGRESS;
-
-               urb->actual_length += uhci_actual_length(ctrlstat);
-
-               if (status)
-                       goto td_error;
-
-               if (uhci_actual_length(ctrlstat) <
-                               uhci_expected_length(td_token(td))) {
-                       if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-                               ret = -EREMOTEIO;
-                               goto err;
-                       }
-
-                       /*
-                        * This URB stopped short of its end.  We have to
-                        * fix up the toggles of the following URBs on the
-                        * queue and restart the queue.
-                        *
-                        * Do this only the first time we encounter the
-                        * short URB.
-                        */
-                       if (!urbp->short_transfer) {
-                               urbp->short_transfer = 1;
-                               urbp->qh->initial_toggle =
-                                               uhci_toggle(td_token(td)) ^ 1;
-                               uhci_fixup_toggles(urbp->qh, 1);
-
-                               td = list_entry(urbp->td_list.prev,
-                                               struct uhci_td, list);
-                               urbp->qh->element = td->link;
-                       }
-                       break;
-               }
-       }
-
-       return 0;
-
-td_error:
-       ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-
-       if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-               /* Some debugging code */
-               dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",
-                               __FUNCTION__, status);
-
-               if (debug > 1 && errbuf) {
-                       /* Print the chain for debugging purposes */
-                       uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-                       lprintk(errbuf);
-               }
-       }
-err:
-
-       /* Note that the queue has stopped and save the next toggle value */
-       urbp->qh->element = UHCI_PTR_TERM;
-       urbp->qh->is_stopped = 1;
-       urbp->qh->needs_fixup = 1;
-       urbp->qh->initial_toggle = uhci_toggle(td_token(td)) ^
-                       (ret == -EREMOTEIO);
-       return ret;
-}
-
 static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
@@ -954,21 +820,162 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
        qh->skel = uhci->skel_bulk_qh;
        ret = uhci_submit_common(uhci, urb, qh);
        if (ret == 0)
-               uhci_inc_fsbr(uhci, urb);
+               uhci_add_fsbr(uhci, urb);
        return ret;
 }
 
-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
+static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
+       int exponent;
+
        /* USB 1.1 interrupt transfers only involve one packet per interval.
         * Drivers can submit URBs of any length, but longer ones will need
         * multiple intervals to complete.
         */
-       qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)];
+
+       /* Figure out which power-of-two queue to use */
+       for (exponent = 7; exponent >= 0; --exponent) {
+               if ((1 << exponent) <= urb->interval)
+                       break;
+       }
+       if (exponent < 0)
+               return -EINVAL;
+       urb->interval = 1 << exponent;
+
+       if (qh->period == 0)
+               qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
+       else if (qh->period != urb->interval)
+               return -EINVAL;         /* Can't change the period */
+
        return uhci_submit_common(uhci, urb, qh);
 }
 
+/*
+ * Fix up the data structures following a short transfer
+ */
+static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
+               struct uhci_qh *qh, struct urb_priv *urbp)
+{
+       struct uhci_td *td;
+       struct list_head *tmp;
+       int ret;
+
+       td = list_entry(urbp->td_list.prev, struct uhci_td, list);
+       if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+               /* When a control transfer is short, we have to restart
+                * the queue at the status stage transaction, which is
+                * the last TD. */
+               WARN_ON(list_empty(&urbp->td_list));
+               qh->element = cpu_to_le32(td->dma_handle);
+               tmp = td->list.prev;
+               ret = -EINPROGRESS;
+
+       } else {
+
+               /* When a bulk/interrupt transfer is short, we have to
+                * fix up the toggles of the following URBs on the queue
+                * before restarting the queue at the next URB. */
+               qh->initial_toggle = uhci_toggle(td_token(qh->post_td)) ^ 1;
+               uhci_fixup_toggles(qh, 1);
+
+               if (list_empty(&urbp->td_list))
+                       td = qh->post_td;
+               qh->element = td->link;
+               tmp = urbp->td_list.prev;
+               ret = 0;
+       }
+
+       /* Remove all the TDs we skipped over, from tmp back to the start */
+       while (tmp != &urbp->td_list) {
+               td = list_entry(tmp, struct uhci_td, list);
+               tmp = tmp->prev;
+
+               uhci_remove_td_from_urbp(td);
+               uhci_free_td(uhci, td);
+       }
+       return ret;
+}
+
+/*
+ * Common result for control, bulk, and interrupt
+ */
+static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
+{
+       struct urb_priv *urbp = urb->hcpriv;
+       struct uhci_qh *qh = urbp->qh;
+       struct uhci_td *td, *tmp;
+       unsigned status;
+       int ret = 0;
+
+       list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
+               unsigned int ctrlstat;
+               int len;
+
+               ctrlstat = td_status(td);
+               status = uhci_status_bits(ctrlstat);
+               if (status & TD_CTRL_ACTIVE)
+                       return -EINPROGRESS;
+
+               len = uhci_actual_length(ctrlstat);
+               urb->actual_length += len;
+
+               if (status) {
+                       ret = uhci_map_status(status,
+                                       uhci_packetout(td_token(td)));
+                       if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+                               /* Some debugging code */
+                               dev_dbg(&urb->dev->dev,
+                                               "%s: failed with status %x\n",
+                                               __FUNCTION__, status);
+
+                               if (debug > 1 && errbuf) {
+                                       /* Print the chain for debugging */
+                                       uhci_show_qh(urbp->qh, errbuf,
+                                                       ERRBUF_LEN, 0);
+                                       lprintk(errbuf);
+                               }
+                       }
+
+               } else if (len < uhci_expected_length(td_token(td))) {
+
+                       /* We received a short packet */
+                       if (urb->transfer_flags & URB_SHORT_NOT_OK)
+                               ret = -EREMOTEIO;
+                       else if (ctrlstat & TD_CTRL_SPD)
+                               ret = 1;
+               }
+
+               uhci_remove_td_from_urbp(td);
+               if (qh->post_td)
+                       uhci_free_td(uhci, qh->post_td);
+               qh->post_td = td;
+
+               if (ret != 0)
+                       goto err;
+       }
+       return ret;
+
+err:
+       if (ret < 0) {
+               /* In case a control transfer gets an error
+                * during the setup stage */
+               urb->actual_length = max(urb->actual_length, 0);
+
+               /* Note that the queue has stopped and save
+                * the next toggle value */
+               qh->element = UHCI_PTR_TERM;
+               qh->is_stopped = 1;
+               qh->needs_fixup = (qh->type != USB_ENDPOINT_XFER_CONTROL);
+               qh->initial_toggle = uhci_toggle(td_token(td)) ^
+                               (ret == -EREMOTEIO);
+
+       } else          /* Short packet received */
+               ret = uhci_fixup_short_transfer(uhci, qh, urbp);
+       return ret;
+}
+
 /*
  * Isochronous transfers
  */
@@ -980,38 +987,57 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
        unsigned long destination, status;
        struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
-       if (urb->number_of_packets > 900)       /* 900? Why? */
+       /* Values must not be too big (could overflow below) */
+       if (urb->interval >= UHCI_NUMFRAMES ||
+                       urb->number_of_packets >= UHCI_NUMFRAMES)
                return -EFBIG;
 
-       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-       destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-       /* Figure out the starting frame number */
-       if (urb->transfer_flags & URB_ISO_ASAP) {
-               if (list_empty(&qh->queue)) {
+       /* Check the period and figure out the starting frame number */
+       if (qh->period == 0) {
+               if (urb->transfer_flags & URB_ISO_ASAP) {
                        uhci_get_current_frame_number(uhci);
-                       urb->start_frame = (uhci->frame_number + 10);
+                       urb->start_frame = uhci->frame_number + 10;
+               } else {
+                       i = urb->start_frame - uhci->last_iso_frame;
+                       if (i <= 0 || i >= UHCI_NUMFRAMES)
+                               return -EINVAL;
+               }
+       } else if (qh->period != urb->interval) {
+               return -EINVAL;         /* Can't change the period */
 
-               } else {                /* Go right after the last one */
-                       struct urb *last_urb;
+       } else {        /* Pick up where the last URB leaves off */
+               if (list_empty(&qh->queue)) {
+                       frame = qh->iso_frame;
+               } else {
+                       struct urb *lurb;
 
-                       last_urb = list_entry(qh->queue.prev,
+                       lurb = list_entry(qh->queue.prev,
                                        struct urb_priv, node)->urb;
-                       urb->start_frame = (last_urb->start_frame +
-                                       last_urb->number_of_packets *
-                                       last_urb->interval);
+                       frame = lurb->start_frame +
+                                       lurb->number_of_packets *
+                                       lurb->interval;
                }
-       } else {
-               /* FIXME: Sanity check */
+               if (urb->transfer_flags & URB_ISO_ASAP)
+                       urb->start_frame = frame;
+               else if (urb->start_frame != frame)
+                       return -EINVAL;
        }
-       urb->start_frame &= (UHCI_NUMFRAMES - 1);
+
+       /* Make sure we won't have to go too far into the future */
+       if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES,
+                       urb->start_frame + urb->number_of_packets *
+                               urb->interval))
+               return -EFBIG;
+
+       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+       destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
        for (i = 0; i < urb->number_of_packets; i++) {
                td = uhci_alloc_td(uhci);
                if (!td)
                        return -ENOMEM;
 
-               uhci_add_td_to_urb(urb, td);
+               uhci_add_td_to_urbp(td, urbp);
                uhci_fill_td(td, status, destination |
                                uhci_explen(urb->iso_frame_desc[i].length),
                                urb->transfer_dma +
@@ -1022,12 +1048,19 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
        td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
        qh->skel = uhci->skel_iso_qh;
+       qh->period = urb->interval;
 
        /* Add the TDs to the frame list */
        frame = urb->start_frame;
        list_for_each_entry(td, &urbp->td_list, list) {
                uhci_insert_td_in_frame_list(uhci, td, frame);
-               frame += urb->interval;
+               frame += qh->period;
+       }
+
+       if (list_empty(&qh->queue)) {
+               qh->iso_packet_desc = &urb->iso_frame_desc[0];
+               qh->iso_frame = urb->start_frame;
+               qh->iso_status = 0;
        }
 
        return 0;
@@ -1035,37 +1068,44 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
 
 static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 {
-       struct uhci_td *td;
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       int status;
-       int i, ret = 0;
-
-       urb->actual_length = urb->error_count = 0;
+       struct uhci_td *td, *tmp;
+       struct urb_priv *urbp = urb->hcpriv;
+       struct uhci_qh *qh = urbp->qh;
 
-       i = 0;
-       list_for_each_entry(td, &urbp->td_list, list) {
+       list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
+               unsigned int ctrlstat;
+               int status;
                int actlength;
-               unsigned int ctrlstat = td_status(td);
 
-               if (ctrlstat & TD_CTRL_ACTIVE)
+               if (uhci_frame_before_eq(uhci->cur_iso_frame, qh->iso_frame))
                        return -EINPROGRESS;
 
-               actlength = uhci_actual_length(ctrlstat);
-               urb->iso_frame_desc[i].actual_length = actlength;
-               urb->actual_length += actlength;
+               uhci_remove_tds_from_frame(uhci, qh->iso_frame);
+
+               ctrlstat = td_status(td);
+               if (ctrlstat & TD_CTRL_ACTIVE) {
+                       status = -EXDEV;        /* TD was added too late? */
+               } else {
+                       status = uhci_map_status(uhci_status_bits(ctrlstat),
+                                       usb_pipeout(urb->pipe));
+                       actlength = uhci_actual_length(ctrlstat);
+
+                       urb->actual_length += actlength;
+                       qh->iso_packet_desc->actual_length = actlength;
+                       qh->iso_packet_desc->status = status;
+               }
 
-               status = uhci_map_status(uhci_status_bits(ctrlstat),
-                               usb_pipeout(urb->pipe));
-               urb->iso_frame_desc[i].status = status;
                if (status) {
                        urb->error_count++;
-                       ret = status;
+                       qh->iso_status = status;
                }
 
-               i++;
+               uhci_remove_td_from_urbp(td);
+               uhci_free_td(uhci, td);
+               qh->iso_frame += qh->period;
+               ++qh->iso_packet_desc;
        }
-
-       return ret;
+       return qh->iso_status;
 }
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
@@ -1099,14 +1139,14 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
        }
        urbp->qh = qh;
 
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_CONTROL:
                ret = uhci_submit_control(uhci, urb, qh);
                break;
-       case PIPE_BULK:
+       case USB_ENDPOINT_XFER_BULK:
                ret = uhci_submit_bulk(uhci, urb, qh);
                break;
-       case PIPE_INTERRUPT:
+       case USB_ENDPOINT_XFER_INT:
                if (list_empty(&qh->queue)) {
                        bustime = usb_check_bandwidth(urb->dev, urb);
                        if (bustime < 0)
@@ -1125,7 +1165,8 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
                        ret = uhci_submit_interrupt(uhci, urb, qh);
                }
                break;
-       case PIPE_ISOCHRONOUS:
+       case USB_ENDPOINT_XFER_ISOC:
+               urb->error_count = 0;
                bustime = usb_check_bandwidth(urb->dev, urb);
                if (bustime < 0) {
                        ret = bustime;
@@ -1146,9 +1187,12 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 
        /* If the new URB is the first and only one on this QH then either
         * the QH is new and idle or else it's unlinked and waiting to
-        * become idle, so we can activate it right away. */
-       if (qh->queue.next == &urbp->node)
+        * become idle, so we can activate it right away.  But only if the
+        * queue isn't stopped. */
+       if (qh->queue.next == &urbp->node && !qh->is_stopped) {
                uhci_activate_qh(uhci, qh);
+               uhci_urbp_wants_fsbr(uhci, urbp);
+       }
        goto done;
 
 err_submit_failed:
@@ -1168,16 +1212,26 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
        struct urb_priv *urbp;
+       struct uhci_qh *qh;
 
        spin_lock_irqsave(&uhci->lock, flags);
        urbp = urb->hcpriv;
        if (!urbp)                      /* URB was never linked! */
                goto done;
+       qh = urbp->qh;
 
        /* Remove Isochronous TDs from the frame list ASAP */
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+       if (qh->type == USB_ENDPOINT_XFER_ISOC) {
                uhci_unlink_isochronous_tds(uhci, urb);
-       uhci_unlink_qh(uhci, urbp->qh);
+               mb();
+
+               /* If the URB has already started, update the QH unlink time */
+               uhci_get_current_frame_number(uhci);
+               if (uhci_frame_before_eq(urb->start_frame, uhci->frame_number))
+                       qh->unlink_frame = uhci->frame_number;
+       }
+
+       uhci_unlink_qh(uhci, qh);
 
 done:
        spin_unlock_irqrestore(&uhci->lock, flags);
@@ -1194,22 +1248,17 @@ __acquires(uhci->lock)
 {
        struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
-       /* Isochronous TDs get unlinked directly from the frame list */
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-               uhci_unlink_isochronous_tds(uhci, urb);
-
-       /* If the URB isn't first on its queue, adjust the link pointer
-        * of the last TD in the previous URB. */
-       else if (qh->queue.next != &urbp->node) {
-               struct urb_priv *purbp;
-               struct uhci_td *ptd, *ltd;
-
-               purbp = list_entry(urbp->node.prev, struct urb_priv, node);
-               ptd = list_entry(purbp->td_list.prev, struct uhci_td,
-                               list);
-               ltd = list_entry(urbp->td_list.prev, struct uhci_td,
-                               list);
-               ptd->link = ltd->link;
+       /* When giving back the first URB in an Isochronous queue,
+        * reinitialize the QH's iso-related members for the next URB. */
+       if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+                       urbp->node.prev == &qh->queue &&
+                       urbp->node.next != &qh->queue) {
+               struct urb *nurb = list_entry(urbp->node.next,
+                               struct urb_priv, node)->urb;
+
+               qh->iso_packet_desc = &nurb->iso_frame_desc[0];
+               qh->iso_frame = nurb->start_frame;
+               qh->iso_status = 0;
        }
 
        /* Take the URB off the QH's queue.  If the queue is now empty,
@@ -1221,16 +1270,15 @@ __acquires(uhci->lock)
                qh->needs_fixup = 0;
        }
 
-       uhci_dec_fsbr(uhci, urb);       /* Safe since it checks */
        uhci_free_urb_priv(uhci, urbp);
 
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_ISOCHRONOUS:
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_ISOC:
                /* Release bandwidth for Interrupt or Isoc. transfers */
                if (urb->bandwidth)
                        usb_release_bandwidth(urb->dev, urb, 1);
                break;
-       case PIPE_INTERRUPT:
+       case USB_ENDPOINT_XFER_INT:
                /* Release bandwidth for Interrupt or Isoc. transfers */
                /* Make sure we don't release if we have a queued URB */
                if (list_empty(&qh->queue) && urb->bandwidth)
@@ -1252,6 +1300,7 @@ __acquires(uhci->lock)
                uhci_unlink_qh(uhci, qh);
 
                /* Bandwidth stuff not yet implemented */
+               qh->period = 0;
        }
 }
 
@@ -1273,17 +1322,10 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
                urbp = list_entry(qh->queue.next, struct urb_priv, node);
                urb = urbp->urb;
 
-               switch (usb_pipetype(urb->pipe)) {
-               case PIPE_CONTROL:
-                       status = uhci_result_control(uhci, urb);
-                       break;
-               case PIPE_ISOCHRONOUS:
+               if (qh->type == USB_ENDPOINT_XFER_ISOC)
                        status = uhci_result_isochronous(uhci, urb);
-                       break;
-               default:        /* PIPE_BULK or PIPE_INTERRUPT */
+               else
                        status = uhci_result_common(uhci, urb);
-                       break;
-               }
                if (status == -EINPROGRESS)
                        break;
 
@@ -1291,31 +1333,43 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
                if (urb->status == -EINPROGRESS)        /* Not dequeued */
                        urb->status = status;
                else
-                       status = -ECONNRESET;
+                       status = ECONNRESET;            /* Not -ECONNRESET */
                spin_unlock(&urb->lock);
 
                /* Dequeued but completed URBs can't be given back unless
                 * the QH is stopped or has finished unlinking. */
-               if (status == -ECONNRESET &&
-                               !(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
-                       return;
+               if (status == ECONNRESET) {
+                       if (QH_FINISHED_UNLINKING(qh))
+                               qh->is_stopped = 1;
+                       else if (!qh->is_stopped)
+                               return;
+               }
 
                uhci_giveback_urb(uhci, qh, urb, regs);
-               if (qh->is_stopped)
+               if (status < 0)
                        break;
        }
 
        /* If the QH is neither stopped nor finished unlinking (normal case),
         * our work here is done. */
- restart:
-       if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh)))
+       if (QH_FINISHED_UNLINKING(qh))
+               qh->is_stopped = 1;
+       else if (!qh->is_stopped)
                return;
 
        /* Otherwise give back each of the dequeued URBs */
+restart:
        list_for_each_entry(urbp, &qh->queue, node) {
                urb = urbp->urb;
                if (urb->status != -EINPROGRESS) {
-                       uhci_save_toggle(qh, urb);
+
+                       /* Fix up the TD links and save the toggles for
+                        * non-Isochronous queues.  For Isochronous queues,
+                        * test for too-recent dequeues. */
+                       if (!uhci_cleanup_queue(uhci, qh, urb)) {
+                               qh->is_stopped = 0;
+                               return;
+                       }
                        uhci_giveback_urb(uhci, qh, urb, regs);
                        goto restart;
                }
@@ -1327,6 +1381,18 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
        if (!list_empty(&qh->queue)) {
                if (qh->needs_fixup)
                        uhci_fixup_toggles(qh, 0);
+
+               /* If the first URB on the queue wants FSBR but its time
+                * limit has expired, set the next TD to interrupt on
+                * completion before reactivating the QH. */
+               urbp = list_entry(qh->queue.next, struct urb_priv, node);
+               if (urbp->fsbr && qh->wait_expired) {
+                       struct uhci_td *td = list_entry(urbp->td_list.next,
+                                       struct uhci_td, list);
+
+                       td->status |= __cpu_to_le32(TD_CTRL_IOC);
+               }
+
                uhci_activate_qh(uhci, qh);
        }
 
@@ -1336,15 +1402,84 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
                uhci_make_qh_idle(uhci, qh);
 }
 
-static void uhci_free_pending_tds(struct uhci_hcd *uhci)
+/*
+ * Check for queues that have made some forward progress.
+ * Returns 0 if the queue is not Isochronous, is ACTIVE, and
+ * has not advanced since last examined; 1 otherwise.
+ *
+ * Early Intel controllers have a bug which causes qh->element sometimes
+ * not to advance when a TD completes successfully.  The queue remains
+ * stuck on the inactive completed TD.  We detect such cases and advance
+ * the element pointer by hand.
+ */
+static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
-       struct uhci_td *td, *tmp;
+       struct urb_priv *urbp = NULL;
+       struct uhci_td *td;
+       int ret = 1;
+       unsigned status;
 
-       list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) {
-               list_del_init(&td->remove_list);
+       if (qh->type == USB_ENDPOINT_XFER_ISOC)
+               goto done;
 
-               uhci_free_td(uhci, td);
+       /* Treat an UNLINKING queue as though it hasn't advanced.
+        * This is okay because reactivation will treat it as though
+        * it has advanced, and if it is going to become IDLE then
+        * this doesn't matter anyway.  Furthermore it's possible
+        * for an UNLINKING queue not to have any URBs at all, or
+        * for its first URB not to have any TDs (if it was dequeued
+        * just as it completed).  So it's not easy in any case to
+        * test whether such queues have advanced. */
+       if (qh->state != QH_STATE_ACTIVE) {
+               urbp = NULL;
+               status = 0;
+
+       } else {
+               urbp = list_entry(qh->queue.next, struct urb_priv, node);
+               td = list_entry(urbp->td_list.next, struct uhci_td, list);
+               status = td_status(td);
+               if (!(status & TD_CTRL_ACTIVE)) {
+
+                       /* We're okay, the queue has advanced */
+                       qh->wait_expired = 0;
+                       qh->advance_jiffies = jiffies;
+                       goto done;
+               }
+               ret = 0;
+       }
+
+       /* The queue hasn't advanced; check for timeout */
+       if (qh->wait_expired)
+               goto done;
+
+       if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
+
+               /* Detect the Intel bug and work around it */
+               if (qh->post_td && qh_element(qh) ==
+                               cpu_to_le32(qh->post_td->dma_handle)) {
+                       qh->element = qh->post_td->link;
+                       qh->advance_jiffies = jiffies;
+                       ret = 1;
+                       goto done;
+               }
+
+               qh->wait_expired = 1;
+
+               /* If the current URB wants FSBR, unlink it temporarily
+                * so that we can safely set the next TD to interrupt on
+                * completion.  That way we'll know as soon as the queue
+                * starts moving again. */
+               if (urbp && urbp->fsbr && !(status & TD_CTRL_IOC))
+                       uhci_unlink_qh(uhci, qh);
+
+       } else {
+               /* Unmoving but not-yet-expired queues keep FSBR alive */
+               if (urbp)
+                       uhci_urbp_wants_fsbr(uhci, urbp);
        }
+
+done:
+       return ret;
 }
 
 /*
@@ -1361,14 +1496,13 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
                return;
        }
        uhci->scan_in_progress = 1;
- rescan:
+rescan:
        uhci->need_rescan = 0;
+       uhci->fsbr_is_wanted = 0;
 
        uhci_clear_next_interrupt(uhci);
        uhci_get_current_frame_number(uhci);
-
-       if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
-               uhci_free_pending_tds(uhci);
+       uhci->cur_iso_frame = uhci->frame_number;
 
        /* Go through all the QH queues and process the URBs in each one */
        for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) {
@@ -1377,33 +1511,30 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
                while ((qh = uhci->next_qh) != uhci->skelqh[i]) {
                        uhci->next_qh = list_entry(qh->node.next,
                                        struct uhci_qh, node);
-                       uhci_scan_qh(uhci, qh, regs);
+
+                       if (uhci_advance_check(uhci, qh)) {
+                               uhci_scan_qh(uhci, qh, regs);
+                               if (qh->state == QH_STATE_ACTIVE) {
+                                       uhci_urbp_wants_fsbr(uhci,
+       list_entry(qh->queue.next, struct urb_priv, node));
+                               }
+                       }
                }
        }
 
+       uhci->last_iso_frame = uhci->cur_iso_frame;
        if (uhci->need_rescan)
                goto rescan;
        uhci->scan_in_progress = 0;
 
-       /* If the controller is stopped, we can finish these off right now */
-       if (uhci->is_stopped)
-               uhci_free_pending_tds(uhci);
+       if (uhci->fsbr_is_on && !uhci->fsbr_is_wanted &&
+                       !uhci->fsbr_expiring) {
+               uhci->fsbr_expiring = 1;
+               mod_timer(&uhci->fsbr_timer, jiffies + FSBR_OFF_DELAY);
+       }
 
-       if (list_empty(&uhci->td_remove_list) &&
-                       list_empty(&uhci->skel_unlink_qh->node))
+       if (list_empty(&uhci->skel_unlink_qh->node))
                uhci_clear_next_interrupt(uhci);
        else
                uhci_set_next_interrupt(uhci);
 }
-
-static void check_fsbr(struct uhci_hcd *uhci)
-{
-       /* For now, don't scan URBs for FSBR timeouts.
-        * Add it back in later... */
-
-       /* Really disable FSBR */
-       if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
-               uhci->fsbrtimeout = 0;
-               uhci->skel_term_qh->link = UHCI_PTR_TERM;
-       }
-}
index df29b8078b54b4e8452029d0e0c533359d4c8908..18c10e150ef37df3e2e78878dace708f4a9bba37 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 /*
  * Version Information
index a6693b0d1c4cc92c20b04957c9630bac3a8224f5..b138dae2b0559dfcff4c79b6e2ccc4fb162714f5 100644 (file)
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
index c222ed13deab49de122ee3a57851a33045f58ef9..36855062eacc8c5c984e5f8a6ca77a76c7c3b31e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Apple USB Touchpad (for post-February 2005 PowerBooks) driver
+ * Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver
  *
  * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
@@ -7,6 +7,7 @@
  * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
  * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
  * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
+ * Copyright (C) 2006      Nicolas Boichat (nicolas@boichat.ch)
  *
  * Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
  *
@@ -32,9 +33,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/input.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 /* Apple has powerbooks which have the keyboard with different Product IDs */
 #define APPLE_VENDOR_ID                0x05AC
 #define GEYSER_ISO_PRODUCT_ID  0x0215
 #define GEYSER_JIS_PRODUCT_ID  0x0216
 
+/* MacBook devices */
+#define GEYSER3_ANSI_PRODUCT_ID        0x0217
+#define GEYSER3_ISO_PRODUCT_ID 0x0218
+#define GEYSER3_JIS_PRODUCT_ID 0x0219
+
 #define ATP_DEVICE(prod)                                       \
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |             \
                       USB_DEVICE_ID_MATCH_INT_CLASS |          \
@@ -65,6 +69,10 @@ static struct usb_device_id atp_table [] = {
        { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) },
        { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) },
 
+       { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) },
+       { ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) },
+       { ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) },
+
        /* Terminating entry */
        { }
 };
@@ -101,6 +109,13 @@ MODULE_DEVICE_TABLE (usb, atp_table);
  */
 #define ATP_THRESHOLD   5
 
+/* MacBook Pro (Geyser 3) initialization constants */
+#define ATP_GEYSER3_MODE_READ_REQUEST_ID 1
+#define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9
+#define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300
+#define ATP_GEYSER3_MODE_REQUEST_INDEX 0
+#define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04
+
 /* Structure to hold all of our device specific stuff */
 struct atp {
        char                    phys[64];
@@ -147,13 +162,22 @@ MODULE_PARM_DESC(debug, "Activate debugging output");
 /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */
 static inline int atp_is_geyser_2(struct atp *dev)
 {
-       int16_t productId = le16_to_cpu(dev->udev->descriptor.idProduct);
+       u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
 
        return (productId == GEYSER_ANSI_PRODUCT_ID) ||
                (productId == GEYSER_ISO_PRODUCT_ID) ||
                (productId == GEYSER_JIS_PRODUCT_ID);
 }
 
+static inline int atp_is_geyser_3(struct atp *dev)
+{
+       u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+       return (productId == GEYSER3_ANSI_PRODUCT_ID) ||
+               (productId == GEYSER3_ISO_PRODUCT_ID) ||
+               (productId == GEYSER3_JIS_PRODUCT_ID);
+}
+
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
                             int *z, int *fingers)
 {
@@ -219,12 +243,33 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
 
        /* drop incomplete datasets */
        if (dev->urb->actual_length != dev->datalen) {
-               dprintk("appletouch: incomplete data package.\n");
+               dprintk("appletouch: incomplete data package"
+                       " (first byte: %d, length: %d).\n",
+                       dev->data[0], dev->urb->actual_length);
                goto exit;
        }
 
        /* reorder the sensors values */
-       if (atp_is_geyser_2(dev)) {
+       if (atp_is_geyser_3(dev)) {
+               memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
+
+               /*
+                * The values are laid out like this:
+                * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
+                * '-' is an unused value.
+                */
+
+               /* read X values */
+               for (i = 0, j = 19; i < 20; i += 2, j += 3) {
+                       dev->xy_cur[i] = dev->data[j + 1];
+                       dev->xy_cur[i + 1] = dev->data[j + 2];
+               }
+               /* read Y values */
+               for (i = 0, j = 1; i < 9; i += 2, j += 3) {
+                       dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
+                       dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
+               }
+       } else if (atp_is_geyser_2(dev)) {
                memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
 
                /*
@@ -267,6 +312,9 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs)
                dev->x_old = dev->y_old = -1;
                memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
 
+               if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */
+                       goto exit;
+
                /* 17" Powerbooks have extra X sensors */
                for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) {
                        if (!dev->xy_cur[i]) continue;
@@ -414,7 +462,50 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
        dev->udev = udev;
        dev->input = input_dev;
        dev->overflowwarn = 0;
-       dev->datalen = (atp_is_geyser_2(dev)?64:81);
+       if (atp_is_geyser_3(dev))
+               dev->datalen = 64;
+       else if (atp_is_geyser_2(dev))
+               dev->datalen = 64;
+       else
+               dev->datalen = 81;
+
+       if (atp_is_geyser_3(dev)) {
+               /*
+                * By default Geyser 3 device sends standard USB HID mouse
+                * packets (Report ID 2). This code changes device mode, so it
+                * sends raw sensor reports (Report ID 5).
+                */
+               char data[8];
+               int size;
+
+               size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                       ATP_GEYSER3_MODE_READ_REQUEST_ID,
+                       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       ATP_GEYSER3_MODE_REQUEST_VALUE,
+                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+               if (size != 8) {
+                       err("Could not do mode read request from device"
+                                                       " (Geyser 3 mode)");
+                       goto err_free_devs;
+               }
+
+               /* Apply the mode switch */
+               data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+               size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       ATP_GEYSER3_MODE_REQUEST_VALUE,
+                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+               if (size != 8) {
+                       err("Could not do mode write request to device"
+                                                       " (Geyser 3 mode)");
+                       goto err_free_devs;
+               }
+               printk("appletouch Geyser 3 inited.\n");
+       }
 
        dev->urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!dev->urb) {
@@ -447,7 +538,15 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
 
        set_bit(EV_ABS, input_dev->evbit);
 
-       if (atp_is_geyser_2(dev)) {
+       if (atp_is_geyser_3(dev)) {
+               /*
+                * MacBook have 20 X sensors, 10 Y sensors
+                */
+               input_set_abs_params(input_dev, ABS_X, 0,
+                                    ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
+               input_set_abs_params(input_dev, ABS_Y, 0,
+                                    ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
+       } else if (atp_is_geyser_2(dev)) {
                /*
                 * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
                 * later.
index 99f986cb6e955d29ea817e2f6f571303b3aac1da..07c8c0e665dd301ced352c6f20e0bb68a0034b98 100644 (file)
@@ -92,9 +92,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 #include <linux/wait.h>
 #include <linux/jiffies.h>
 
index ab1a1ae24be95936844679f044b1089ca3bf4d80..ea71de81ca6b571290b303cd0ab0f3744b26d202 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation.
  */
 
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #define DRIVER_DESC    "ATI/Philips USB RF remote driver"
 #define DRIVER_VERSION "0.1"
index 435273e7c85cb5912ec9cc22ded58dec3b6e76aa..b9fb9687f9266f287addecae037dd5045b7034a6 100644 (file)
@@ -944,21 +944,28 @@ static void hid_reset(void *_hid)
        dev_dbg(&hid->intf->dev, "resetting device\n");
        rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
        if (rc_lock >= 0) {
-               rc = usb_reset_device(hid->dev);
+               rc = usb_reset_composite_device(hid->dev, hid->intf);
                if (rc_lock)
                        usb_unlock_device(hid->dev);
        }
        clear_bit(HID_RESET_PENDING, &hid->iofl);
 
-       if (rc == 0) {
-               hid->retry_delay = 0;
-               if (hid_start_in(hid))
+       switch (rc) {
+       case 0:
+               if (!test_bit(HID_IN_RUNNING, &hid->iofl))
                        hid_io_error(hid);
-       } else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR))
+               break;
+       default:
                err("can't reset device, %s-%s/input%d, status %d",
                                hid->dev->bus->bus_name,
                                hid->dev->devpath,
                                hid->ifnum, rc);
+               /* FALLTHROUGH */
+       case -EHOSTUNREACH:
+       case -ENODEV:
+       case -EINTR:
+               break;
+       }
 }
 
 /* Main I/O error handler */
@@ -1374,9 +1381,6 @@ void hid_close(struct hid_device *hid)
 
 #define USB_VENDOR_ID_PANJIT           0x134c
 
-#define USB_VENDOR_ID_SILVERCREST      0x062a
-#define USB_DEVICE_ID_SILVERCREST_KB   0x0201
-
 /*
  * Initialize all reports
  */
@@ -1461,9 +1465,6 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_ONTRAK           0x0a07
 #define USB_DEVICE_ID_ONTRAK_ADU100    0x0064
 
-#define USB_VENDOR_ID_TANGTOP          0x0d3d
-#define USB_DEVICE_ID_TANGTOP_USBPS2   0x0001
-
 #define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
@@ -1520,12 +1521,6 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
 #define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
 
-#define USB_VENDOR_ID_CHICONY          0x04f2
-#define USB_DEVICE_ID_CHICONY_USBHUB_KB        0x0100
-
-#define USB_VENDOR_ID_BTC              0x046e
-#define USB_DEVICE_ID_BTC_KEYBOARD     0x5303
-
 #define USB_VENDOR_ID_VERNIER          0x08f7
 #define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
 #define USB_DEVICE_ID_VERNIER_GOTEMP   0x0002
@@ -1549,20 +1544,13 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_DEVICE_ID_LD_MACHINETEST   0x2040
 
 #define USB_VENDOR_ID_APPLE            0x05ac
-#define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
 
 #define USB_VENDOR_ID_CHERRY           0x046a
 #define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
 
-#define USB_VENDOR_ID_HP               0x03f0
-#define USB_DEVICE_ID_HP_USBHUB_KB     0x020c
-
-#define USB_VENDOR_ID_IBM              0x04b3
-#define USB_DEVICE_ID_IBM_USBHUB_KB    0x3005
-
-#define USB_VENDOR_ID_CREATIVELABS     0x062a
-#define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201
-
+#define USB_VENDOR_ID_YEALINK          0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K      0xb001
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -1671,6 +1659,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF + 3, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+       { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
 
        { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
@@ -1680,16 +1669,9 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
-       { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
-       { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_USBHUB_KB, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-       { USB_VENDOR_ID_SILVERCREST, USB_DEVICE_ID_SILVERCREST_KB, HID_QUIRK_NOGET },
 
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
        { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
 
@@ -1711,6 +1693,9 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN },
        { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN },
        { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0217, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0219, HID_QUIRK_POWERBOOK_HAS_FN },
        { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN },
        { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN },
 
@@ -1794,6 +1779,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                        (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct)))
                                quirks = hid_blacklist[n].quirks;
 
+       /* Many keyboards and mice don't like to be polled for reports,
+        * so we will always set the HID_QUIRK_NOGET flag for them. */
+       if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
+               if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||
+                       interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+                               quirks |= HID_QUIRK_NOGET;
+       }
+
        if (quirks & HID_QUIRK_IGNORE)
                return NULL;
 
@@ -2080,11 +2073,29 @@ static int hid_resume(struct usb_interface *intf)
        int status;
 
        clear_bit(HID_SUSPENDED, &hid->iofl);
+       hid->retry_delay = 0;
        status = hid_start_in(hid);
        dev_dbg(&intf->dev, "resume status %d\n", status);
        return status;
 }
 
+/* Treat USB reset pretty much the same as suspend/resume */
+static void hid_pre_reset(struct usb_interface *intf)
+{
+       /* FIXME: What if the interface is already suspended? */
+       hid_suspend(intf, PMSG_ON);
+}
+
+static void hid_post_reset(struct usb_interface *intf)
+{
+       struct usb_device *dev = interface_to_usbdev (intf);
+
+       hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
+       /* FIXME: Any more reinitialization needed? */
+
+       hid_resume(intf);
+}
+
 static struct usb_device_id hid_usb_ids [] = {
        { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
                .bInterfaceClass = USB_INTERFACE_CLASS_HID },
@@ -2099,6 +2110,8 @@ static struct usb_driver hid_driver = {
        .disconnect =   hid_disconnect,
        .suspend =      hid_suspend,
        .resume =       hid_resume,
+       .pre_reset =    hid_pre_reset,
+       .post_reset =   hid_post_reset,
        .id_table =     hid_usb_ids,
 };
 
index 25bc85f8ce39ba7368fe90a8fa1c1359df19aaba..028e1ad89f5d96471f08bbb36a96c6d3ee33e121 100644 (file)
@@ -29,9 +29,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #undef DEBUG
 
@@ -567,16 +565,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        break;
        }
 
-       set_bit(usage->type, input->evbit);
-
-       while (usage->code <= max && test_and_set_bit(usage->code, bit))
-               usage->code = find_next_zero_bit(bit, max + 1, usage->code);
-
-       if (usage->code > max)
-               goto ignore;
-
-       if (((device->quirks & (HID_QUIRK_2WHEEL_POWERMOUSE)) && (usage->hid == 0x00010032)))
-               map_rel(REL_HWHEEL);
+       if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
+               if (usage->hid == HID_GD_Z)
+                       map_rel(REL_HWHEEL);
+               else if (usage->code == BTN_1)
+                       map_key(BTN_2);
+               else if (usage->code == BTN_2)
+                       map_key(BTN_1);
+       }
 
        if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
                 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
@@ -586,6 +582,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
                goto ignore;
 
+       set_bit(usage->type, input->evbit);
+
+       while (usage->code <= max && test_and_set_bit(usage->code, bit))
+               usage->code = find_next_zero_bit(bit, max + 1, usage->code);
+
+       if (usage->code > max)
+               goto ignore;
+
+
        if (usage->type == EV_ABS) {
 
                int a = field->logical_minimum;
@@ -647,6 +652,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
+       if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
+               input_event(input, usage->type, usage->code, -value);
+               return;
+       }
+
        if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
                input_event(input, usage->type, REL_HWHEEL, value);
                return;
index 9c62837b5b899c2fcb40389725bee142b619db6c..778e575de35230831bebbfaa983a555f3754b40b 100644 (file)
 
 #define USB_INTERFACE_CLASS_HID                3
 
+/*
+ * USB HID interface subclass and protocol codes
+ */
+
+#define USB_INTERFACE_SUBCLASS_BOOT    1
+#define USB_INTERFACE_PROTOCOL_KEYBOARD        1
+#define USB_INTERFACE_PROTOCOL_MOUSE   2
+
 /*
  * HID class requests
  */
@@ -247,10 +255,11 @@ struct hid_item {
 #define HID_QUIRK_2WHEEL_MOUSE_HACK_7          0x00000080
 #define HID_QUIRK_2WHEEL_MOUSE_HACK_5          0x00000100
 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON         0x00000200
-#define HID_QUIRK_2WHEEL_POWERMOUSE            0x00000400
+#define HID_QUIRK_MIGHTYMOUSE                  0x00000400
 #define HID_QUIRK_CYMOTION                     0x00000800
 #define HID_QUIRK_POWERBOOK_HAS_FN             0x00001000
 #define HID_QUIRK_POWERBOOK_FN_ON              0x00002000
+#define HID_QUIRK_INVERT_HWHEEL                        0x00004000
 
 /*
  * This is the global environment of the parser. This information is
index 7618ae5c104f7d7c999b4d37a51498e2358f80fc..5c570cc703f355af8adf2198967424e62aa968da 100644 (file)
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 /* only an 8 byte buffer necessary for a single packet */
 #define ITM_BUFSIZE                    8
index f6d5cead542bd734de71e58a1f0a0f5914697135..604ade356eadd680d0851c66d151b76f596ac7f2 100644 (file)
@@ -1,12 +1,9 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 #include <asm/unaligned.h>
-#include <asm/byteorder.h>
 
 /*
  * Version Information
index 3d911976f378ca9386fe2484cc1b7f177237f26c..70af985b5db9ad50d63f791b99f8bb1ee648134d 100644 (file)
@@ -18,9 +18,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #define DRIVER_VERSION "v0.1"
 #define DRIVER_AUTHOR  "Michael Downey <downey@zymeta.com>"
index f018953a5485238e088ad1b9483177b077d3ae2b..4fdee4db0729d3e165258957d1f5bfb3c58d1552 100644 (file)
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #define MTOUCHUSB_MIN_XC                0x0
 #define MTOUCHUSB_MAX_RAW_XC            0x4000
index fdf0f788062c3fadd64d520db8854cac1e6c0084..b3c0d0c3eae998b45ab1de1344fe935ee9b3c95d 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #define POWERMATE_VENDOR       0x077d  /* Griffin Technology, Inc. */
 #define POWERMATE_PRODUCT_NEW  0x0410  /* Griffin PowerMate */
index 697c5e573a115cbe1d38548448032705f4846543..da7b0bf51aff80d8b6eda7334ddfd3627c0401ff 100644 (file)
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #define TOUCHKIT_MIN_XC                        0x0
 #define TOUCHKIT_MAX_XC                        0x07ff
index 2f3edc26cb5057f2da7eba68e06b1482eb246b30..5067a6ae650f8bfb220dc7d29e85bfcb39d66eb5 100644 (file)
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/input.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 /*
  * Version Information
index af526135d210752c09e346566c909fe046322c67..446935b671d989e72e270752fffa77e33a5348ae 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 /*
  * Version Information
index e9a07c1e905b12025e2dbc72521dab4cd50ac42f..3b175aa482cdd276c362e1ef1dec01512adbfc49 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 
 #define DRIVER_VERSION         "v0.3"
index cf84c6096f299721be8c24cb66d8baa9d43aad45..369461a70b7238c6226b6e2b3daecf54dce5d97d 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/input.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 #include <asm/unaligned.h>
-#include <asm/byteorder.h>
 
 /*
  * Version Information
index e278489a80c6520941fe30723ea50c305717bd72..cfd4a4e04334fbcfbf78e139b58188f242c6549a 100644 (file)
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/input.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #define DRIVER_VERSION "v0.0.5"
 #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
index 37d2f0ba0319c28e73e688394c27c3f65ab28459..24aedbb20f032e405c8d5714ed8f3b36ad13a718 100644 (file)
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/input.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/rwsem.h>
-#include <linux/usb.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 
 #include "map_to_7segment.h"
 #include "yealink.h"
index 8ba6a701e9c144afcb42473fa166e08ca959c3b8..daa486dde8cfe665ef1bed16d2dae0ea1ed07f1c 100644 (file)
@@ -88,6 +88,20 @@ config USB_LED
          To compile this driver as a module, choose M here: the
          module will be called usbled.
 
+config USB_CY7C63
+       tristate "Cypress CY7C63xxx USB driver support"
+       depends on USB
+       help
+         Say Y here if you want to connect a Cypress CY7C63xxx
+         micro controller to your computer's USB port. This driver
+         supports the pre-programmed devices (incl. firmware) by
+         AK Modul-Bus Computer GmbH.
+
+         Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html
+
+         To compile this driver as a module, choose M here: the
+         module will be called cy7c63.
+
 config USB_CYTHERM
        tristate "Cypress USB thermometer driver support"
        depends on USB
@@ -137,6 +151,15 @@ config USB_IDMOUSE
 
          See also <http://www.fs.tum.de/~echtler/idmouse/>.
 
+config USB_APPLEDISPLAY
+       tristate "Apple Cinema Display support"
+       depends on USB
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       help
+         Say Y here if you want to control the backlight of Apple Cinema
+         Displays over USB. This driver provides a sysfs interface.
+
 source "drivers/usb/misc/sisusbvga/Kconfig"
 
 config USB_LD
index 6c693bc68e2e8f2ce71df7fe793c988ed3db0c17..f25a972272973b563ccc5677171e45d06d5467df 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_USB_AUERSWALD)    += auerswald.o
+obj-$(CONFIG_USB_CY7C63)       += cy7c63.o
 obj-$(CONFIG_USB_CYTHERM)      += cytherm.o
 obj-$(CONFIG_USB_EMI26)                += emi26.o
 obj-$(CONFIG_USB_EMI62)                += emi62.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO)        += phidgetservo.o
 obj-$(CONFIG_USB_RIO500)       += rio500.o
 obj-$(CONFIG_USB_TEST)         += usbtest.o
 obj-$(CONFIG_USB_USS720)       += uss720.o
+obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
 
 obj-$(CONFIG_USB_SISUSBVGA)    += sisusbvga/
 
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
new file mode 100644 (file)
index 0000000..bfde82f
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Apple Cinema Display driver
+ *
+ * Copyright (C) 2006  Michael Hanselmann (linux-kernel@hansmi.ch)
+ *
+ * Thanks to Caskey L. Dickson for his work with acdctl.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/backlight.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+#define APPLE_VENDOR_ID                0x05AC
+
+#define USB_REQ_GET_REPORT     0x01
+#define USB_REQ_SET_REPORT     0x09
+
+#define ACD_USB_TIMEOUT                250
+
+#define ACD_USB_EDID           0x0302
+#define ACD_USB_BRIGHTNESS     0x0310
+
+#define ACD_BTN_NONE           0
+#define ACD_BTN_BRIGHT_UP      3
+#define ACD_BTN_BRIGHT_DOWN    4
+
+#define ACD_URB_BUFFER_LEN     2
+#define ACD_MSG_BUFFER_LEN     2
+
+#define APPLEDISPLAY_DEVICE(prod)                              \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |             \
+                      USB_DEVICE_ID_MATCH_INT_CLASS |          \
+                      USB_DEVICE_ID_MATCH_INT_PROTOCOL,        \
+       .idVendor = APPLE_VENDOR_ID,                            \
+       .idProduct = (prod),                                    \
+       .bInterfaceClass = USB_CLASS_HID,                       \
+       .bInterfaceProtocol = 0x00
+
+/* table of devices that work with this driver */
+static struct usb_device_id appledisplay_table [] = {
+       { APPLEDISPLAY_DEVICE(0x9218) },
+       { APPLEDISPLAY_DEVICE(0x9219) },
+       { APPLEDISPLAY_DEVICE(0x921d) },
+
+       /* Terminating entry */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, appledisplay_table);
+
+/* Structure to hold all of our device specific stuff */
+struct appledisplay {
+       struct usb_device *udev;        /* usb device */
+       struct urb *urb;                /* usb request block */
+       struct backlight_device *bd;    /* backlight device */
+       char *urbdata;                  /* interrupt URB data buffer */
+       char *msgdata;                  /* control message data buffer */
+
+       struct work_struct work;
+       int button_pressed;
+       spinlock_t lock;
+};
+
+static atomic_t count_displays = ATOMIC_INIT(0);
+static struct workqueue_struct *wq;
+
+static void appledisplay_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct appledisplay *pdata = urb->context;
+       unsigned long flags;
+       int retval;
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -EOVERFLOW:
+               printk(KERN_ERR "appletouch: OVERFLOW with data "
+                       "length %d, actual length is %d\n",
+                       ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* This urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d",
+                       __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d",
+                       __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       spin_lock_irqsave(&pdata->lock, flags);
+
+       switch(pdata->urbdata[1]) {
+       case ACD_BTN_BRIGHT_UP:
+       case ACD_BTN_BRIGHT_DOWN:
+               pdata->button_pressed = 1;
+               queue_work(wq, &pdata->work);
+               break;
+       case ACD_BTN_NONE:
+       default:
+               pdata->button_pressed = 0;
+               break;
+       }
+
+       spin_unlock_irqrestore(&pdata->lock, flags);
+
+exit:
+       retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
+       if (retval) {
+               err("%s - usb_submit_urb failed with result %d",
+                       __FUNCTION__, retval);
+       }
+}
+
+static int appledisplay_bl_update_status(struct backlight_device *bd)
+{
+       struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+       int retval;
+
+       pdata->msgdata[0] = 0x10;
+       pdata->msgdata[1] = bd->props->brightness;
+
+       retval = usb_control_msg(
+               pdata->udev,
+               usb_sndctrlpipe(pdata->udev, 0),
+               USB_REQ_SET_REPORT,
+               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               ACD_USB_BRIGHTNESS,
+               0,
+               pdata->msgdata, 2,
+               ACD_USB_TIMEOUT);
+
+       return retval;
+}
+
+static int appledisplay_bl_get_brightness(struct backlight_device *bd)
+{
+       struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+       int retval;
+
+       retval = usb_control_msg(
+               pdata->udev,
+               usb_rcvctrlpipe(pdata->udev, 0),
+               USB_REQ_GET_REPORT,
+               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               ACD_USB_BRIGHTNESS,
+               0,
+               pdata->msgdata, 2,
+               ACD_USB_TIMEOUT);
+
+       if (retval < 0)
+               return retval;
+       else
+               return pdata->msgdata[1];
+}
+
+static struct backlight_properties appledisplay_bl_data = {
+       .owner          = THIS_MODULE,
+       .get_brightness = appledisplay_bl_get_brightness,
+       .update_status  = appledisplay_bl_update_status,
+       .max_brightness = 0xFF
+};
+
+static void appledisplay_work(void *private)
+{
+       struct appledisplay *pdata = private;
+       int retval;
+
+       up(&pdata->bd->sem);
+       retval = appledisplay_bl_get_brightness(pdata->bd);
+       if (retval >= 0)
+               pdata->bd->props->brightness = retval;
+       down(&pdata->bd->sem);
+
+       /* Poll again in about 125ms if there's still a button pressed */
+       if (pdata->button_pressed)
+               schedule_delayed_work(&pdata->work, HZ / 8);
+}
+
+static int appledisplay_probe(struct usb_interface *iface,
+       const struct usb_device_id *id)
+{
+       struct appledisplay *pdata;
+       struct usb_device *udev = interface_to_usbdev(iface);
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       int int_in_endpointAddr = 0;
+       int i, retval = -ENOMEM, brightness;
+       char bl_name[20];
+
+       /* set up the endpoint information */
+       /* use only the first interrupt-in endpoint */
+       iface_desc = iface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if (!int_in_endpointAddr &&
+                   (endpoint->bEndpointAddress & USB_DIR_IN) &&
+                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                    USB_ENDPOINT_XFER_INT)) {
+                       /* we found an interrupt in endpoint */
+                       int_in_endpointAddr = endpoint->bEndpointAddress;
+                       break;
+               }
+       }
+       if (!int_in_endpointAddr) {
+               err("Could not find int-in endpoint");
+               return -EIO;
+       }
+
+       /* allocate memory for our device state and initialize it */
+       pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL);
+       if (!pdata) {
+               retval = -ENOMEM;
+               err("Out of memory");
+               goto error;
+       }
+
+       pdata->udev = udev;
+
+       spin_lock_init(&pdata->lock);
+       INIT_WORK(&pdata->work, appledisplay_work, pdata);
+
+       /* Allocate buffer for control messages */
+       pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL);
+       if (!pdata->msgdata) {
+               retval = -ENOMEM;
+               err("appledisplay: Allocating buffer for control messages "
+                       "failed");
+               goto error;
+       }
+
+       /* Allocate interrupt URB */
+       pdata->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!pdata->urb) {
+               retval = -ENOMEM;
+               err("appledisplay: Allocating URB failed");
+               goto error;
+       }
+
+       /* Allocate buffer for interrupt data */
+       pdata->urbdata = usb_buffer_alloc(pdata->udev, ACD_URB_BUFFER_LEN,
+               GFP_KERNEL, &pdata->urb->transfer_dma);
+       if (!pdata->urbdata) {
+               retval = -ENOMEM;
+               err("appledisplay: Allocating URB buffer failed");
+               goto error;
+       }
+
+       /* Configure interrupt URB */
+       usb_fill_int_urb(pdata->urb, udev,
+               usb_rcvintpipe(udev, int_in_endpointAddr),
+               pdata->urbdata, ACD_URB_BUFFER_LEN, appledisplay_complete,
+               pdata, 1);
+       if (usb_submit_urb(pdata->urb, GFP_KERNEL)) {
+               retval = -EIO;
+               err("appledisplay: Submitting URB failed");
+               goto error;
+       }
+
+       /* Register backlight device */
+       snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
+               atomic_inc_return(&count_displays) - 1);
+       pdata->bd = backlight_device_register(bl_name, pdata,
+                                               &appledisplay_bl_data);
+       if (IS_ERR(pdata->bd)) {
+               err("appledisplay: Backlight registration failed");
+               goto error;
+       }
+
+       /* Try to get brightness */
+       up(&pdata->bd->sem);
+       brightness = appledisplay_bl_get_brightness(pdata->bd);
+       down(&pdata->bd->sem);
+
+       if (brightness < 0) {
+               retval = brightness;
+               err("appledisplay: Error while getting initial brightness: %d", retval);
+               goto error;
+       }
+
+       /* Set brightness in backlight device */
+       up(&pdata->bd->sem);
+       pdata->bd->props->brightness = brightness;
+       down(&pdata->bd->sem);
+
+       /* save our data pointer in the interface device */
+       usb_set_intfdata(iface, pdata);
+
+       printk(KERN_INFO "appledisplay: Apple Cinema Display connected\n");
+
+       return 0;
+
+error:
+       if (pdata) {
+               if (pdata->urb) {
+                       usb_kill_urb(pdata->urb);
+                       if (pdata->urbdata)
+                               usb_buffer_free(pdata->udev, ACD_URB_BUFFER_LEN,
+                                       pdata->urbdata, pdata->urb->transfer_dma);
+                       usb_free_urb(pdata->urb);
+               }
+               if (pdata->bd)
+                       backlight_device_unregister(pdata->bd);
+               kfree(pdata->msgdata);
+       }
+       usb_set_intfdata(iface, NULL);
+       kfree(pdata);
+       return retval;
+}
+
+static void appledisplay_disconnect(struct usb_interface *iface)
+{
+       struct appledisplay *pdata = usb_get_intfdata(iface);
+
+       if (pdata) {
+               usb_kill_urb(pdata->urb);
+               cancel_delayed_work(&pdata->work);
+               backlight_device_unregister(pdata->bd);
+               usb_buffer_free(pdata->udev, ACD_URB_BUFFER_LEN,
+                       pdata->urbdata, pdata->urb->transfer_dma);
+               usb_free_urb(pdata->urb);
+               kfree(pdata->msgdata);
+               kfree(pdata);
+       }
+
+       printk(KERN_INFO "appledisplay: Apple Cinema Display disconnected\n");
+}
+
+static struct usb_driver appledisplay_driver = {
+       .name           = "appledisplay",
+       .probe          = appledisplay_probe,
+       .disconnect     = appledisplay_disconnect,
+       .id_table       = appledisplay_table,
+};
+
+static int __init appledisplay_init(void)
+{
+       wq = create_singlethread_workqueue("appledisplay");
+       if (!wq) {
+               err("Could not create work queue\n");
+               return -ENOMEM;
+       }
+
+       return usb_register(&appledisplay_driver);
+}
+
+static void __exit appledisplay_exit(void)
+{
+       flush_workqueue(wq);
+       destroy_workqueue(wq);
+       usb_deregister(&appledisplay_driver);
+}
+
+MODULE_AUTHOR("Michael Hanselmann");
+MODULE_DESCRIPTION("Apple Cinema Display driver");
+MODULE_LICENSE("GPL");
+
+module_init(appledisplay_init);
+module_exit(appledisplay_exit);
diff --git a/drivers/usb/misc/cy7c63.c b/drivers/usb/misc/cy7c63.c
new file mode 100644 (file)
index 0000000..8a1c10b
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+* cy7c63.c
+*
+* Copyright (c) 2006 Oliver Bock (bock@fh-wolfenbuettel.de)
+*
+*      This driver is based on the Cypress Thermometer USB Driver by
+*      Marcus Maul and the 2.0 version of Greg Kroah-Hartman's
+*      USB Skeleton driver.
+*
+*      Is is a generic driver for the Cypress CY7C63000 family.
+*      For the time being it enables you to toggle the single I/O ports
+*      of the device.
+*
+*      Supported vendors:      AK Modul-Bus Computer GmbH
+*      Supported devices:      CY7C63001A-PC (to be continued...)
+*      Supported functions:    Read/Write Ports (to be continued...)
+*
+*      Chipsets families:      CY7C63000, CY7C63001, CY7C63100, CY7C63101
+*
+*
+*      This program is free software; you can redistribute it and/or
+*      modify it under the terms of the GNU General Public License as
+*      published by the Free Software Foundation, version 2.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+
+#define DRIVER_AUTHOR          "Oliver Bock (bock@fh-wolfenbuettel.de)"
+#define DRIVER_DESC            "Cypress CY7C63xxx USB driver"
+
+#define CY7C63_VENDOR_ID       0xa2c
+#define CY7C63_PRODUCT_ID      0x8
+
+#define CY7C63_READ_PORT       0x4
+#define CY7C63_WRITE_PORT      0x5
+#define CY7C63_READ_RAM                0x2
+#define CY7C63_WRITE_RAM       0x3
+#define CY7C63_READ_ROM                0x1
+
+#define CY7C63_READ_PORT_ID0   0
+#define CY7C63_WRITE_PORT_ID0  0
+#define CY7C63_READ_PORT_ID1   0x2
+#define CY7C63_WRITE_PORT_ID1  1
+
+#define CY7C63_MAX_REQSIZE     8
+
+
+/* table of devices that work with this driver */
+static struct usb_device_id cy7c63_table [] = {
+       { USB_DEVICE(CY7C63_VENDOR_ID, CY7C63_PRODUCT_ID) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, cy7c63_table);
+
+/* structure to hold all of our device specific stuff */
+struct cy7c63 {
+       struct usb_device *     udev;
+       char                    port0;
+       char                    port1;
+};
+
+/* used to send usb control messages to device */
+int vendor_command(struct cy7c63 *dev, unsigned char request,
+                        unsigned char address, unsigned char data) {
+
+       int retval = 0;
+       unsigned int pipe;
+       unsigned char *iobuf;
+
+       /* allocate some memory for the i/o buffer*/
+       iobuf = kzalloc(CY7C63_MAX_REQSIZE, GFP_KERNEL);
+       if (!iobuf) {
+               dev_err(&dev->udev->dev, "Out of memory!\n");
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
+
+       /* prepare usb control message and send it upstream */
+       pipe = usb_rcvctrlpipe(dev->udev, 0);
+       retval = usb_control_msg(dev->udev, pipe, request,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                               address, data, iobuf, CY7C63_MAX_REQSIZE,
+                               USB_CTRL_GET_TIMEOUT);
+
+       /* store returned data (more READs to be added!) */
+       switch (request) {
+               case CY7C63_READ_PORT:
+                       if (address == CY7C63_READ_PORT_ID0) {
+                               dev->port0 = iobuf[1];
+                               dev_dbg(&dev->udev->dev,
+                                       "READ_PORT0 returned: %d\n",dev->port0);
+                       }
+                       else if (address == CY7C63_READ_PORT_ID1) {
+                               dev->port1 = iobuf[1];
+                               dev_dbg(&dev->udev->dev,
+                                       "READ_PORT1 returned: %d\n",dev->port1);
+                       }
+                       break;
+       }
+
+       kfree(iobuf);
+error:
+       return retval;
+}
+
+#define get_set_port(num,read_id,write_id) \
+static ssize_t set_port##num(struct device *dev, struct device_attribute *attr,        \
+                                       const char *buf, size_t count) {        \
+                                                                               \
+       int value;                                                              \
+       int result = 0;                                                         \
+                                                                               \
+       struct usb_interface *intf = to_usb_interface(dev);                     \
+       struct cy7c63 *cyp = usb_get_intfdata(intf);                            \
+                                                                               \
+       dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", num);                 \
+                                                                               \
+       /* validate input data */                                               \
+       if (sscanf(buf, "%d", &value) < 1) {                                    \
+               result = -EINVAL;                                               \
+               goto error;                                                     \
+       }                                                                       \
+       if (value>255 || value<0) {                                             \
+               result = -EINVAL;                                               \
+               goto error;                                                     \
+       }                                                                       \
+                                                                               \
+       result = vendor_command(cyp, CY7C63_WRITE_PORT, write_id,               \
+                                        (unsigned char)value);                 \
+                                                                               \
+       dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n",result);    \
+error:                                                                         \
+       return result < 0 ? result : count;                                     \
+}                                                                              \
+                                                                               \
+static ssize_t get_port##num(struct device *dev,                               \
+                                struct device_attribute *attr, char *buf) {    \
+                                                                               \
+       int result = 0;                                                         \
+                                                                               \
+       struct usb_interface *intf = to_usb_interface(dev);                     \
+       struct cy7c63 *cyp = usb_get_intfdata(intf);                            \
+                                                                               \
+       dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", num);                  \
+                                                                               \
+       result = vendor_command(cyp, CY7C63_READ_PORT, read_id, 0);             \
+                                                                               \
+       dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);   \
+                                                                               \
+       return sprintf(buf, "%d", cyp->port##num);                              \
+}                                                                              \
+static DEVICE_ATTR(port##num, S_IWUGO | S_IRUGO, get_port##num, set_port##num);
+
+get_set_port(0, CY7C63_READ_PORT_ID0, CY7C63_WRITE_PORT_ID0);
+get_set_port(1, CY7C63_READ_PORT_ID1, CY7C63_WRITE_PORT_ID1);
+
+static int cy7c63_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id) {
+
+       struct cy7c63 *dev = NULL;
+       int retval = -ENOMEM;
+
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               dev_err(&dev->udev->dev, "Out of memory!\n");
+               goto error;
+       }
+
+       dev->udev = usb_get_dev(interface_to_usbdev(interface));
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       /* create device attribute files */
+       device_create_file(&interface->dev, &dev_attr_port0);
+       device_create_file(&interface->dev, &dev_attr_port1);
+
+       /* let the user know what node this device is now attached to */
+       dev_info(&interface->dev,
+               "Cypress CY7C63xxx device now attached\n");
+
+       retval = 0;
+error:
+       return retval;
+}
+
+static void cy7c63_disconnect(struct usb_interface *interface) {
+
+       struct cy7c63 *dev;
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       /* remove device attribute files */
+       device_remove_file(&interface->dev, &dev_attr_port0);
+       device_remove_file(&interface->dev, &dev_attr_port1);
+
+       usb_put_dev(dev->udev);
+
+       dev_info(&interface->dev,
+               "Cypress CY7C63xxx device now disconnected\n");
+
+       kfree(dev);
+}
+
+static struct usb_driver cy7c63_driver = {
+       .name = "cy7c63",
+       .probe = cy7c63_probe,
+       .disconnect = cy7c63_disconnect,
+       .id_table = cy7c63_table,
+};
+
+static int __init cy7c63_init(void) {
+
+       int result;
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&cy7c63_driver);
+       if (result) {
+               err("Function usb_register failed! Error number: %d\n", result);
+       }
+
+       return result;
+}
+
+static void __exit cy7c63_exit(void) {
+
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&cy7c63_driver);
+}
+
+module_init(cy7c63_init);
+module_exit(cy7c63_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_LICENSE("GPL");
index 997db5d8e35b703249f2c13bc86e920bf3508ee1..13aeea2026ccb6a916efca8a178ff65c6e274486 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * USB PhidgetInterfaceKit driver 1.0
  *
- * Copyright (C) 2004 Sean Young <sean@mess.org>
+ * Copyright (C) 2004, 2006 Sean Young <sean@mess.org>
+ * Copyright (C) 2005 Daniel Saakes <daniel@saakes.net>
  * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,6 +26,7 @@
 
 #define USB_VENDOR_ID_GLAB             0x06c2
 #define USB_DEVICE_ID_INTERFACEKIT004  0x0040
+#define USB_DEVICE_ID_INTERFACEKIT01616        0x0044
 #define USB_DEVICE_ID_INTERFACEKIT888  0x0045
 #define USB_DEVICE_ID_INTERFACEKIT047  0x0051
 #define USB_DEVICE_ID_INTERFACEKIT088  0x0053
@@ -32,7 +34,9 @@
 #define USB_VENDOR_ID_WISEGROUP                0x0925
 #define USB_DEVICE_ID_INTERFACEKIT884  0x8201
 
-#define MAX_INTERFACES                 8
+#define MAX_INTERFACES                 16
+
+#define URB_INT_SIZE                   8
 
 struct driver_interfacekit {
        int sensors;
@@ -52,19 +56,24 @@ ifkit(8, 8, 8, 0);
 ifkit(0, 4, 7, 1);
 ifkit(8, 8, 4, 0);
 ifkit(0, 8, 8, 1);
+ifkit(0, 16, 16, 0);
 
-struct phidget_interfacekit {
+struct interfacekit {
        struct usb_device *udev;
        struct usb_interface *intf;
        struct driver_interfacekit *ifkit;
-       int outputs[MAX_INTERFACES];
-       int inputs[MAX_INTERFACES];
-       int sensors[MAX_INTERFACES];
+       unsigned long outputs;
+       u8 inputs[MAX_INTERFACES];
+       u16 sensors[MAX_INTERFACES];
        u8 lcd_files_on;
 
        struct urb *irq;
        unsigned char *data;
        dma_addr_t data_dma;
+
+       struct work_struct do_notify;
+       unsigned long input_events;
+       unsigned long sensor_events;
 };
 
 static struct usb_device_id id_table[] = {
@@ -76,33 +85,33 @@ static struct usb_device_id id_table[] = {
                .driver_info = (kernel_ulong_t)&ph_047},
        {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088),
                .driver_info = (kernel_ulong_t)&ph_088},
+       {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT01616),
+               .driver_info = (kernel_ulong_t)&ph_01616},
        {USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_INTERFACEKIT884),
                .driver_info = (kernel_ulong_t)&ph_884},
        {}
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static int change_outputs(struct phidget_interfacekit *kit, int output_num, int enable)
+static int change_outputs(struct interfacekit *kit, int output_num, int enable)
 {
-       unsigned char *buffer;
+       u8 *buffer;
        int retval;
-       int n;
+
+       if (enable)
+               set_bit(output_num, &kit->outputs);
+       else
+               clear_bit(output_num, &kit->outputs);
 
        buffer = kzalloc(4, GFP_KERNEL);
        if (!buffer) {
-               dev_err(&kit->udev->dev, "%s - out of memory\n",
-                       __FUNCTION__);
+               dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
+       buffer[0] = (u8)kit->outputs;
+       buffer[1] = (u8)(kit->outputs >> 8);
 
-       kit->outputs[output_num] = enable;
-       for (n=0; n<8; n++) {
-               if (kit->outputs[n]) {
-                       buffer[0] |= 1 << n;
-               }
-       }
-
-       dev_dbg(&kit->udev->dev, "sending data: %02x\n", buffer[0]);
+       dev_dbg(&kit->udev->dev, "sending data: 0x%04x\n", (u16)kit->outputs);
 
        retval = usb_control_msg(kit->udev,
                         usb_sndctrlpipe(kit->udev, 0),
@@ -116,10 +125,10 @@ static int change_outputs(struct phidget_interfacekit *kit, int output_num, int
        return retval < 0 ? retval : 0;
 }
 
-static int change_string(struct phidget_interfacekit *kit, const char *display, unsigned char row)
+static int change_string(struct interfacekit *kit, const char *display, unsigned char row)
 {
        unsigned char *buffer;
-        unsigned char *form_buffer;
+       unsigned char *form_buffer;
        int retval = -ENOMEM;
        int i,j, len, buf_ptr;
        
@@ -175,7 +184,7 @@ exit:
 static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)     \
 {                                                                                      \
        struct usb_interface *intf = to_usb_interface(dev);                             \
-       struct phidget_interfacekit *kit = usb_get_intfdata(intf);                      \
+       struct interfacekit *kit = usb_get_intfdata(intf);                              \
        change_string(kit, buf, number - 1);                                            \
        return count;                                                                   \
 }                                                                                      \
@@ -186,7 +195,7 @@ set_lcd_line(2);
 static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct usb_interface *intf = to_usb_interface(dev);
-       struct phidget_interfacekit *kit = usb_get_intfdata(intf);
+       struct interfacekit *kit = usb_get_intfdata(intf);
        int enabled;
        unsigned char *buffer;
        int retval = -ENOMEM;
@@ -220,7 +229,7 @@ exit:
 }
 static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight);
 
-static void remove_lcd_files(struct phidget_interfacekit *kit)
+static void remove_lcd_files(struct interfacekit *kit)
 {
        if (kit->lcd_files_on) {
                dev_dbg(&kit->udev->dev, "Removing lcd files\n");
@@ -233,7 +242,7 @@ static void remove_lcd_files(struct phidget_interfacekit *kit)
 static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct usb_interface *intf = to_usb_interface(dev);
-       struct phidget_interfacekit *kit = usb_get_intfdata(intf);
+       struct interfacekit *kit = usb_get_intfdata(intf);
        int enable;
        
        if (kit->ifkit->has_lcd == 0)
@@ -263,10 +272,10 @@ static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files);
 
 static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)
 {
-       struct phidget_interfacekit *kit = urb->context;
+       struct interfacekit *kit = urb->context;
        unsigned char *buffer = kit->data;
+       int i, level, sensor;
        int status;
-       int n;
 
        switch (urb->status) {
        case 0:                 /* success */
@@ -280,22 +289,63 @@ static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)
                goto resubmit;
        }
 
-       for (n=0; n<8; n++) {
-               kit->inputs[n] = buffer[1] & (1 << n) ? 1 : 0;
+       /* digital inputs */
+       if (kit->ifkit->inputs == 16) {
+               for (i=0; i < 8; i++) {
+                       level = (buffer[0] >> i) & 1;
+                       if (kit->inputs[i] != level) {
+                               kit->inputs[i] = level;
+                               set_bit(i, &kit->input_events);
+                       }
+                       level = (buffer[1] >> i) & 1;
+                       if (kit->inputs[8 + i] != level) {
+                               kit->inputs[8 + i] = level;
+                               set_bit(8 + i, &kit->input_events);
+                       }
+               }
+       }
+       else if (kit->ifkit->inputs == 8) {
+               for (i=0; i < 8; i++) {
+                       level = (buffer[1] >> i) & 1;
+                       if (kit->inputs[i] != level) {
+                               kit->inputs[i] = level;
+                               set_bit(i, &kit->input_events);
+                       }
+               }
        }
 
-       if (buffer[0] & 1) {
-               kit->sensors[4] = buffer[2] + (buffer[3] & 0x0f) * 256;
-               kit->sensors[5] = buffer[4] + (buffer[3] & 0xf0) * 16;
-               kit->sensors[6] = buffer[5] + (buffer[6] & 0x0f) * 256;
-               kit->sensors[7] = buffer[7] + (buffer[6] & 0xf0) * 16;
-       } else {
-               kit->sensors[0] = buffer[2] + (buffer[3] & 0x0f) * 256;
-               kit->sensors[1] = buffer[4] + (buffer[3] & 0xf0) * 16;
-               kit->sensors[2] = buffer[5] + (buffer[6] & 0x0f) * 256;
-               kit->sensors[3] = buffer[7] + (buffer[6] & 0xf0) * 16;
+       /* analog inputs */
+       if (kit->ifkit->sensors) {
+               sensor = (buffer[0] & 1) ? 4 : 0;
+
+               level = buffer[2] + (buffer[3] & 0x0f) * 256;
+               if (level != kit->sensors[sensor]) {
+                       kit->sensors[sensor] = level;
+                       set_bit(sensor, &kit->sensor_events);
+               }
+               sensor++;
+               level = buffer[4] + (buffer[3] & 0xf0) * 16;
+               if (level != kit->sensors[sensor]) {
+                       kit->sensors[sensor] = level;
+                       set_bit(sensor, &kit->sensor_events);
+               }
+               sensor++;
+               level = buffer[5] + (buffer[6] & 0x0f) * 256;
+               if (level != kit->sensors[sensor]) {
+                       kit->sensors[sensor] = level;
+                       set_bit(sensor, &kit->sensor_events);
+               }
+               sensor++;
+               level = buffer[7] + (buffer[6] & 0xf0) * 16;
+               if (level != kit->sensors[sensor]) {
+                       kit->sensors[sensor] = level;
+                       set_bit(sensor, &kit->sensor_events);
+               }
        }
 
+       if (kit->input_events || kit->sensor_events)
+               schedule_work(&kit->do_notify);
+
 resubmit:
        status = usb_submit_urb(urb, SLAB_ATOMIC);
        if (status)
@@ -304,20 +354,40 @@ resubmit:
                        kit->udev->devpath, status);
 }
 
+static void do_notify(void *data)
+{
+       struct interfacekit *kit = data;
+       int i;
+       char sysfs_file[8];
+
+       for (i=0; i<kit->ifkit->inputs; i++) {
+               if (test_and_clear_bit(i, &kit->input_events)) {
+                       sprintf(sysfs_file, "input%d", i + 1);
+                       sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
+               }
+       }
+
+       for (i=0; i<kit->ifkit->sensors; i++) {
+               if (test_and_clear_bit(i, &kit->sensor_events)) {
+                       sprintf(sysfs_file, "sensor%d", i + 1);
+                       sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
+               }
+       }
+}
+
 #define show_set_output(value)         \
-static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf,   \
+static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf,   \
                                                        size_t count)   \
 {                                                                      \
        struct usb_interface *intf = to_usb_interface(dev);             \
-       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+       struct interfacekit *kit = usb_get_intfdata(intf);              \
        int enabled;                                                    \
        int retval;                                                     \
                                                                        \
-       if (sscanf(buf, "%d", &enabled) < 1) {                          \
+       if (sscanf(buf, "%d", &enabled) < 1)                            \
                return -EINVAL;                                         \
-       }                                                               \
                                                                        \
-       retval = change_outputs(kit, value - 1, enabled ? 1 : 0);       \
+       retval = change_outputs(kit, value - 1, enabled);               \
                                                                        \
        return retval ? retval : count;                                 \
 }                                                                      \
@@ -325,9 +395,9 @@ static ssize_t set_output##value(struct device *dev, struct device_attribute *at
 static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf)        \
 {                                                                      \
        struct usb_interface *intf = to_usb_interface(dev);             \
-       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+       struct interfacekit *kit = usb_get_intfdata(intf);              \
                                                                        \
-       return sprintf(buf, "%d\n", kit->outputs[value - 1]);           \
+       return sprintf(buf, "%d\n", !!test_bit(value - 1, &kit->outputs));\
 }                                                                      \
 static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO,                   \
                show_output##value, set_output##value);
@@ -338,15 +408,23 @@ show_set_output(4);
 show_set_output(5);
 show_set_output(6);
 show_set_output(7);
-show_set_output(8);    /* should be MAX_INTERFACES - 1 */
+show_set_output(8);
+show_set_output(9);
+show_set_output(10);
+show_set_output(11);
+show_set_output(12);
+show_set_output(13);
+show_set_output(14);
+show_set_output(15);
+show_set_output(16);
 
 #define show_input(value)      \
 static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \
 {                                                                      \
        struct usb_interface *intf = to_usb_interface(dev);             \
-       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+       struct interfacekit *kit = usb_get_intfdata(intf);              \
                                                                        \
-       return sprintf(buf, "%d\n", kit->inputs[value - 1]);            \
+       return sprintf(buf, "%d\n", (int)kit->inputs[value - 1]);       \
 }                                                                      \
 static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL);
 
@@ -357,15 +435,23 @@ show_input(4);
 show_input(5);
 show_input(6);
 show_input(7);
-show_input(8);         /* should be MAX_INTERFACES - 1 */
+show_input(8);
+show_input(9);
+show_input(10);
+show_input(11);
+show_input(12);
+show_input(13);
+show_input(14);
+show_input(15);
+show_input(16);
 
 #define show_sensor(value)     \
 static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf)        \
 {                                                                      \
        struct usb_interface *intf = to_usb_interface(dev);             \
-       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+       struct interfacekit *kit = usb_get_intfdata(intf);              \
                                                                        \
-       return sprintf(buf, "%d\n", kit->sensors[value - 1]);           \
+       return sprintf(buf, "%d\n", (int)kit->sensors[value - 1]);      \
 }                                                                      \
 static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL);
 
@@ -376,16 +462,16 @@ show_sensor(4);
 show_sensor(5);
 show_sensor(6);
 show_sensor(7);
-show_sensor(8);                /* should be MAX_INTERFACES - 1 */
+show_sensor(8);
 
 static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usb_host_interface *interface;
        struct usb_endpoint_descriptor *endpoint;
-       struct phidget_interfacekit *kit;
+       struct interfacekit *kit;
        struct driver_interfacekit *ifkit;
-       int pipe, maxp;
+       int pipe, maxp, rc = -ENOMEM;
 
        ifkit = (struct driver_interfacekit *)id->driver_info;
        if (!ifkit)
@@ -405,29 +491,23 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
        maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
        
        kit = kzalloc(sizeof(*kit), GFP_KERNEL);
-       if (kit  == NULL) {
-               dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__);
-               return -ENOMEM;
-       }
-       kit->ifkit = ifkit;
+       if (!kit)
+               goto out;
 
-       kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma);
-       if (!kit->data) {
-               kfree(kit);
-               return -ENOMEM;
-       }
+       kit->ifkit = ifkit;
+       kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma);
+       if (!kit->data)
+               goto out;
 
        kit->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!kit->irq) {
-               usb_buffer_free(dev, 8, kit->data, kit->data_dma);
-               kfree(kit);
-               return -ENOMEM;
-       }
+       if (!kit->irq)
+               goto out;
 
        kit->udev = usb_get_dev(dev);
        kit->intf = intf;
+       INIT_WORK(&kit->do_notify, do_notify, kit);
        usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data,
-                       (maxp > 8 ? 8 : maxp),
+                       maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
                        interfacekit_irq, kit, endpoint->bInterval);
        kit->irq->transfer_dma = kit->data_dma;
        kit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -435,7 +515,8 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
        usb_set_intfdata(intf, kit);
 
        if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
-               return -EIO;
+               rc = -EIO;
+               goto out;
        }
 
        if (ifkit->outputs >= 4) {
@@ -444,12 +525,22 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
                device_create_file(&intf->dev, &dev_attr_output3);
                device_create_file(&intf->dev, &dev_attr_output4);
        }
-       if (ifkit->outputs == 8) {
+       if (ifkit->outputs >= 8) {
                device_create_file(&intf->dev, &dev_attr_output5);
                device_create_file(&intf->dev, &dev_attr_output6);
                device_create_file(&intf->dev, &dev_attr_output7);
                device_create_file(&intf->dev, &dev_attr_output8);
        } 
+       if (ifkit->outputs == 16) {
+               device_create_file(&intf->dev, &dev_attr_output9);
+               device_create_file(&intf->dev, &dev_attr_output10);
+               device_create_file(&intf->dev, &dev_attr_output11);
+               device_create_file(&intf->dev, &dev_attr_output12);
+               device_create_file(&intf->dev, &dev_attr_output13);
+               device_create_file(&intf->dev, &dev_attr_output14);
+               device_create_file(&intf->dev, &dev_attr_output15);
+               device_create_file(&intf->dev, &dev_attr_output16);
+       }
 
        if (ifkit->inputs >= 4) {
                device_create_file(&intf->dev, &dev_attr_input1);
@@ -457,12 +548,22 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
                device_create_file(&intf->dev, &dev_attr_input3);
                device_create_file(&intf->dev, &dev_attr_input4);
        }
-       if (ifkit->inputs == 8) {
+       if (ifkit->inputs >= 8) {
                device_create_file(&intf->dev, &dev_attr_input5);
                device_create_file(&intf->dev, &dev_attr_input6);
                device_create_file(&intf->dev, &dev_attr_input7);
                device_create_file(&intf->dev, &dev_attr_input8);
        }
+       if (ifkit->inputs == 16) {
+               device_create_file(&intf->dev, &dev_attr_input9);
+               device_create_file(&intf->dev, &dev_attr_input10);
+               device_create_file(&intf->dev, &dev_attr_input11);
+               device_create_file(&intf->dev, &dev_attr_input12);
+               device_create_file(&intf->dev, &dev_attr_input13);
+               device_create_file(&intf->dev, &dev_attr_input14);
+               device_create_file(&intf->dev, &dev_attr_input15);
+               device_create_file(&intf->dev, &dev_attr_input16);
+       }
 
        if (ifkit->sensors >= 4) {
                device_create_file(&intf->dev, &dev_attr_sensor1);
@@ -475,9 +576,8 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
                device_create_file(&intf->dev, &dev_attr_sensor6);
                device_create_file(&intf->dev, &dev_attr_sensor7);
        }
-       if (ifkit->sensors == 8) {
+       if (ifkit->sensors == 8)
                device_create_file(&intf->dev, &dev_attr_sensor8);
-       }
 
        if (ifkit->has_lcd)
                device_create_file(&intf->dev, &dev_attr_lcd);
@@ -486,29 +586,56 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
                        ifkit->sensors, ifkit->inputs, ifkit->outputs);
 
        return 0;
+
+out:
+       if (kit) {
+               if (kit->irq)
+                       usb_free_urb(kit->irq);
+               if (kit->data)
+                       usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma);
+               kfree(kit);
+       }
+
+       return rc;
 }
 
 static void interfacekit_disconnect(struct usb_interface *interface)
 {
-       struct phidget_interfacekit *kit;
+       struct interfacekit *kit;
 
        kit = usb_get_intfdata(interface);
        usb_set_intfdata(interface, NULL);
        if (!kit)
                return;
 
+       usb_kill_urb(kit->irq);
+       usb_free_urb(kit->irq);
+       usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma);
+
+       cancel_delayed_work(&kit->do_notify);
+
        if (kit->ifkit->outputs >= 4) {
                device_remove_file(&interface->dev, &dev_attr_output1);
                device_remove_file(&interface->dev, &dev_attr_output2);
                device_remove_file(&interface->dev, &dev_attr_output3);
                device_remove_file(&interface->dev, &dev_attr_output4);
        }
-       if (kit->ifkit->outputs == 8) {
+       if (kit->ifkit->outputs >= 8) {
                device_remove_file(&interface->dev, &dev_attr_output5);
                device_remove_file(&interface->dev, &dev_attr_output6);
                device_remove_file(&interface->dev, &dev_attr_output7);
                device_remove_file(&interface->dev, &dev_attr_output8);
        }
+       if (kit->ifkit->outputs == 16) {
+               device_remove_file(&interface->dev, &dev_attr_output9);
+               device_remove_file(&interface->dev, &dev_attr_output10);
+               device_remove_file(&interface->dev, &dev_attr_output11);
+               device_remove_file(&interface->dev, &dev_attr_output12);
+               device_remove_file(&interface->dev, &dev_attr_output13);
+               device_remove_file(&interface->dev, &dev_attr_output14);
+               device_remove_file(&interface->dev, &dev_attr_output15);
+               device_remove_file(&interface->dev, &dev_attr_output16);
+       }
 
        if (kit->ifkit->inputs >= 4) {
                device_remove_file(&interface->dev, &dev_attr_input1);
@@ -516,12 +643,22 @@ static void interfacekit_disconnect(struct usb_interface *interface)
                device_remove_file(&interface->dev, &dev_attr_input3);
                device_remove_file(&interface->dev, &dev_attr_input4);
        }
-       if (kit->ifkit->inputs == 8) {
+       if (kit->ifkit->inputs >= 8) {
                device_remove_file(&interface->dev, &dev_attr_input5);
                device_remove_file(&interface->dev, &dev_attr_input6);
                device_remove_file(&interface->dev, &dev_attr_input7);
                device_remove_file(&interface->dev, &dev_attr_input8);
        }
+       if (kit->ifkit->inputs == 16) {
+               device_remove_file(&interface->dev, &dev_attr_input9);
+               device_remove_file(&interface->dev, &dev_attr_input10);
+               device_remove_file(&interface->dev, &dev_attr_input11);
+               device_remove_file(&interface->dev, &dev_attr_input12);
+               device_remove_file(&interface->dev, &dev_attr_input13);
+               device_remove_file(&interface->dev, &dev_attr_input14);
+               device_remove_file(&interface->dev, &dev_attr_input15);
+               device_remove_file(&interface->dev, &dev_attr_input16);
+       }
 
        if (kit->ifkit->sensors >= 4) {
                device_remove_file(&interface->dev, &dev_attr_sensor1);
@@ -534,19 +671,15 @@ static void interfacekit_disconnect(struct usb_interface *interface)
                device_remove_file(&interface->dev, &dev_attr_sensor6);
                device_remove_file(&interface->dev, &dev_attr_sensor7);
        }
-       if (kit->ifkit->sensors == 8) {
+       if (kit->ifkit->sensors == 8)
                device_remove_file(&interface->dev, &dev_attr_sensor8);
-       }
+
        if (kit->ifkit->has_lcd)
                device_remove_file(&interface->dev, &dev_attr_lcd);
 
        dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
                kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
 
-       usb_kill_urb(kit->irq);
-       usb_free_urb(kit->irq);
-       usb_buffer_free(kit->udev, 8, kit->data, kit->data_dma);
-
        usb_put_dev(kit->udev);
        kfree(kit);
 }
index 196c8794a73cf161d3262059d648fe397125d64d..738bd7c7451f160c88d79c2be0b5a41f5221d716 100644 (file)
@@ -37,6 +37,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
@@ -52,6 +53,7 @@
 #include <linux/vmalloc.h>
 
 #include "sisusb.h"
+#include "sisusb_init.h"
 
 #ifdef INCL_SISUSB_CON
 #include <linux/font.h>
 /* Forward declarations / clean-up routines */
 
 #ifdef INCL_SISUSB_CON
-int    sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-int    sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-int    sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data);
-int    sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data);
-int    sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor);
-int    sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor);
-int    sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand);
-
-int    sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int    sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
-int    sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
-int    sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
-int    sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
-                       u32 dest, int length, size_t *bytes_written);
-
-int    sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
-
-extern int  SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-extern int  SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
-
-extern void sisusb_init_concode(void);
-extern int  sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
-extern void sisusb_console_exit(struct sisusb_usb_data *sisusb);
-
-extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
-
-extern int  sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
-               u8 *arg, int cmapsz, int ch512, int dorecalc,
-               struct vc_data *c, int fh, int uplock);
-
 static int sisusb_first_vc = 0;
 static int sisusb_last_vc = 0;
 module_param_named(first, sisusb_first_vc, int, 0);
@@ -102,7 +74,7 @@ MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES
 
 static struct usb_driver sisusb_driver;
 
-DECLARE_MUTEX(disconnect_sem);
+DEFINE_MUTEX(disconnect_mutex);
 
 static void
 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
@@ -1359,9 +1331,6 @@ sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
 }
 #endif
 
-#ifndef INCL_SISUSB_CON
-static
-#endif
 int
 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
 {
@@ -1371,9 +1340,6 @@ sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
        return ret;
 }
 
-#ifndef INCL_SISUSB_CON
-static
-#endif
 int
 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
 {
@@ -1383,9 +1349,6 @@ sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
        return ret;
 }
 
-#ifndef INCL_SISUSB_CON
-static
-#endif
 int
 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
                                                        u8 myand, u8 myor)
@@ -1415,18 +1378,12 @@ sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
        return ret;
 }
 
-#ifndef INCL_SISUSB_CON
-static
-#endif
 int
 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
 {
        return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
 }
 
-#ifndef INCL_SISUSB_CON
-static
-#endif
 int
 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
 {
@@ -1448,6 +1405,8 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
        return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
 }
 
+#if 0
+
 int
 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
 {
@@ -1460,6 +1419,8 @@ sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
        return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
 }
 
+#endif  /*  0  */
+
 int
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
                        u32 dest, int length, size_t *bytes_written)
@@ -2552,39 +2513,39 @@ sisusb_open(struct inode *inode, struct file *file)
        struct usb_interface *interface;
        int subminor = iminor(inode);
 
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
                printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
                                subminor);
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
        if (!(sisusb = usb_get_intfdata(interface))) {
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        if (!sisusb->present || !sisusb->ready) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
        if (sisusb->isopen) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                return -EBUSY;
        }
 
        if (!sisusb->devinit) {
                if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
                        if (sisusb_init_gfxdevice(sisusb, 0)) {
-                               up(&sisusb->lock);
-                               up(&disconnect_sem);
+                               mutex_unlock(&sisusb->lock);
+                               mutex_unlock(&disconnect_mutex);
                                printk(KERN_ERR
                                        "sisusbvga[%d]: Failed to initialize "
                                        "device\n",
@@ -2592,8 +2553,8 @@ sisusb_open(struct inode *inode, struct file *file)
                                return -EIO;
                        }
                } else {
-                       up(&sisusb->lock);
-                       up(&disconnect_sem);
+                       mutex_unlock(&sisusb->lock);
+                       mutex_unlock(&disconnect_mutex);
                        printk(KERN_ERR
                                "sisusbvga[%d]: Device not attached to "
                                "USB 2.0 hub\n",
@@ -2609,9 +2570,9 @@ sisusb_open(struct inode *inode, struct file *file)
 
        file->private_data = sisusb;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 
        return 0;
 }
@@ -2642,14 +2603,14 @@ sisusb_release(struct inode *inode, struct file *file)
        struct sisusb_usb_data *sisusb;
        int myminor;
 
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return -ENODEV;
        }
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        if (sisusb->present) {
                /* Wait for all URBs to finish if device still present */
@@ -2662,12 +2623,12 @@ sisusb_release(struct inode *inode, struct file *file)
        sisusb->isopen = 0;
        file->private_data = NULL;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        /* decrement the usage count on our device */
        kref_put(&sisusb->kref, sisusb_delete);
 
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 
        return 0;
 }
@@ -2685,11 +2646,11 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
                return -ENODEV;
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        /* Sanity check */
        if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return -ENODEV;
        }
 
@@ -2784,7 +2745,7 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
                    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
 
                if (count != 4) {
-                       up(&sisusb->lock);
+                       mutex_unlock(&sisusb->lock);
                        return -EINVAL;
                }
 
@@ -2808,7 +2769,7 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 
        (*ppos) += bytes_read;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return errno ? errno : bytes_read;
 }
@@ -2827,11 +2788,11 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
                return -ENODEV;
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        /* Sanity check */
        if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return -ENODEV;
        }
 
@@ -2930,7 +2891,7 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
                    (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
 
                if (count != 4) {
-                       up(&sisusb->lock);
+                       mutex_unlock(&sisusb->lock);
                        return -EINVAL;
                }
 
@@ -2956,7 +2917,7 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count,
 
        (*ppos) += bytes_written;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return errno ? errno : bytes_written;
 }
@@ -2970,11 +2931,11 @@ sisusb_lseek(struct file *file, loff_t offset, int orig)
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
                return -ENODEV;
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        /* Sanity check */
        if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return -ENODEV;
        }
 
@@ -2994,7 +2955,7 @@ sisusb_lseek(struct file *file, loff_t offset, int orig)
                        ret = -EINVAL;
        }
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
        return ret;
 }
 
@@ -3136,7 +3097,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
                return -ENODEV;
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        /* Sanity check */
        if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
@@ -3193,7 +3154,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        }
 
 err_out:
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
        return retval;
 }
 
@@ -3258,7 +3219,7 @@ static int sisusb_probe(struct usb_interface *intf,
        }
        kref_init(&sisusb->kref);
 
-       init_MUTEX(&(sisusb->lock));
+       mutex_init(&(sisusb->lock));
 
        /* Register device */
        if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
@@ -3429,9 +3390,9 @@ static void sisusb_disconnect(struct usb_interface *intf)
         * protect all other routines from the disconnect
         * case, not the other way round.
         */
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        /* Wait for all URBs to complete and kill them in case (MUST do) */
        if (!sisusb_wait_all_out_complete(sisusb))
@@ -3462,12 +3423,12 @@ static void sisusb_disconnect(struct usb_interface *intf)
        sisusb->present = 0;
        sisusb->ready = 0;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        /* decrement our usage count */
        kref_put(&sisusb->kref, sisusb_delete);
 
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 
        printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
 }
index a716825d1f9b2d8799d3c852f06dc2ea91648437..8e1120a6480647b4d8d97803205d3ca2016a88a9 100644 (file)
@@ -41,6 +41,8 @@
 #define SISUSB_NEW_CONFIG_COMPAT
 #endif
 
+#include <linux/mutex.h>
+
 /* For older kernels, support for text consoles is by default
  * off. To ensable text console support, change the following:
  */
 #define INCL_SISUSB_CON                1
 #endif
 
-#ifdef INCL_SISUSB_CON
 #include <linux/console.h>
 #include <linux/vt_kern.h>
 #include "sisusb_struct.h"
-#endif
 
 /* USB related */
 
@@ -116,7 +116,7 @@ struct sisusb_usb_data {
        struct usb_interface *interface;
        struct kref kref;
        wait_queue_head_t wait_q;       /* for syncind and timeouts */
-       struct semaphore lock;          /* general race avoidance */
+       struct mutex lock;              /* general race avoidance */
        unsigned int ifnum;             /* interface number of the USB device */
        int minor;                      /* minor (for logging clarity) */
        int isopen;                     /* !=0 if open */
index be5c1a25ae21c1282b7a5d4637b8036b632e2192..fb48feca835308ba30a351a37e748ea5282522d8 100644 (file)
@@ -48,6 +48,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/vmalloc.h>
 
 #include "sisusb.h"
+#include "sisusb_init.h"
 
 #ifdef INCL_SISUSB_CON
-extern int sisusb_setreg(struct sisusb_usb_data *, int, u8);
-extern int sisusb_getreg(struct sisusb_usb_data *, int, u8 *);
-extern int sisusb_setidxreg(struct sisusb_usb_data *, int, u8, u8);
-extern int sisusb_getidxreg(struct sisusb_usb_data *, int, u8, u8 *);
-extern int sisusb_setidxregor(struct sisusb_usb_data *, int, u8, u8);
-extern int sisusb_setidxregand(struct sisusb_usb_data *, int, u8, u8);
-extern int sisusb_setidxregandor(struct sisusb_usb_data *, int, u8, u8, u8);
-
-extern int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-extern int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
-extern int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
-extern int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
-extern int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
-                       u32 dest, int length, size_t *bytes_written);
-
-extern void sisusb_delete(struct kref *kref);
-extern int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
-
-extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
 
 #define sisusbcon_writew(val, addr)    (*(addr) = (val))
 #define sisusbcon_readw(addr)          (*(addr))
@@ -102,8 +85,6 @@ static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES];
 /* Forward declaration */
 static const struct consw sisusb_con;
 
-extern struct semaphore disconnect_sem;
-
 static inline void
 sisusbcon_memsetw(u16 *s, u16 c, unsigned int count)
 {
@@ -194,11 +175,11 @@ sisusb_get_sisusb_lock_and_check(unsigned short console)
        if (!(sisusb = sisusb_get_sisusb(console)))
                return NULL;
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        if (!sisusb_sisusb_valid(sisusb) ||
            !sisusb->havethisconsole[console]) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return NULL;
        }
 
@@ -236,18 +217,18 @@ sisusbcon_init(struct vc_data *c, int init)
         * are set up/restored.
         */
 
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return;
        }
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        if (!sisusb_sisusb_valid(sisusb)) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                return;
        }
 
@@ -284,9 +265,9 @@ sisusbcon_init(struct vc_data *c, int init)
        if (!*c->vc_uni_pagedir_loc)
                con_set_default_unimap(c);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 
        if (init) {
                c->vc_cols = cols;
@@ -306,14 +287,14 @@ sisusbcon_deinit(struct vc_data *c)
         * and others, ie not under our control.
         */
 
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
        if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
-               up(&disconnect_sem);
+               mutex_unlock(&disconnect_mutex);
                return;
        }
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        /* Clear ourselves in mysisusbs */
        mysisusbs[c->vc_num] = NULL;
@@ -332,12 +313,12 @@ sisusbcon_deinit(struct vc_data *c)
                }
        }
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        /* decrement the usage count on our sisusb */
        kref_put(&sisusb->kref, sisusb_delete);
 
-       up(&disconnect_sem);
+       mutex_unlock(&disconnect_mutex);
 }
 
 /* interface routine */
@@ -417,7 +398,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
 #endif
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return;
        }
 
@@ -425,7 +406,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
        sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
                                (u32)SISUSB_HADDR(x, y), 2, &written);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 }
 
 /* Interface routine */
@@ -453,14 +434,14 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
                sisusbcon_writew(sisusbcon_readw(s++), dest++);
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return;
        }
 
        sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
                                (u32)SISUSB_HADDR(x, y), count * 2, &written);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 }
 
 /* Interface routine */
@@ -504,7 +485,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
        }
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return;
        }
 
@@ -514,7 +495,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
        sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
                                (u32)SISUSB_HADDR(x, y), length, &written);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 }
 
 /* Interface routine */
@@ -576,7 +557,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
 #endif
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return;
        }
 
@@ -586,7 +567,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
        sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
                                (u32)SISUSB_HADDR(dx, dy), length, &written);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 }
 
 /* interface routine */
@@ -609,7 +590,7 @@ sisusbcon_switch(struct vc_data *c)
 
        /* Don't write to screen if in gfx mode */
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return 0;
        }
 
@@ -618,7 +599,7 @@ sisusbcon_switch(struct vc_data *c)
         * as origin.
         */
        if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
                return 0;
        }
@@ -635,7 +616,7 @@ sisusbcon_switch(struct vc_data *c)
                                (u32)SISUSB_HADDR(0, 0),
                                length, &written);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return 0;
 }
@@ -657,7 +638,7 @@ sisusbcon_save_screen(struct vc_data *c)
        /* sisusb->lock is down */
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return;
        }
 
@@ -669,7 +650,7 @@ sisusbcon_save_screen(struct vc_data *c)
        sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin,
                                                                length);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 }
 
 /* interface routine */
@@ -690,7 +671,7 @@ sisusbcon_set_palette(struct vc_data *c, unsigned char *table)
        /* sisusb->lock is down */
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return -EINVAL;
        }
 
@@ -705,7 +686,7 @@ sisusbcon_set_palette(struct vc_data *c, unsigned char *table)
                        break;
        }
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return 0;
 }
@@ -728,7 +709,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
                sisusb->is_gfx = blank ? 1 : 0;
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return 0;
        }
 
@@ -777,7 +758,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
                        cr63  = 0x40;
                        break;
                default:
-                       up(&sisusb->lock);
+                       mutex_unlock(&sisusb->lock);
                        return -EINVAL;
                }
 
@@ -788,7 +769,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
 
        }
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return ret;
 }
@@ -809,7 +790,7 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines)
        /* sisusb->lock is down */
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return 0;
        }
 
@@ -849,7 +830,7 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines)
 
        sisusbcon_set_start_address(sisusb, c);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return 1;
 }
@@ -867,7 +848,7 @@ sisusbcon_cursor(struct vc_data *c, int mode)
        /* sisusb->lock is down */
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return;
        }
 
@@ -879,7 +860,7 @@ sisusbcon_cursor(struct vc_data *c, int mode)
        if (mode == CM_ERASE) {
                sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20);
                sisusb->sisusb_cursor_size_to = -1;
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return;
        }
 
@@ -919,7 +900,7 @@ sisusbcon_cursor(struct vc_data *c, int mode)
                sisusb->sisusb_cursor_size_to   = to;
        }
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 }
 
 static int
@@ -961,7 +942,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
        sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
                                (u32)SISUSB_HADDR(0, t), length, &written);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return 1;
 }
@@ -994,7 +975,7 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
        /* sisusb->lock is down */
 
        if (sisusb_is_inactive(c, sisusb)) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return 0;
        }
 
@@ -1084,7 +1065,7 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
 
        c->vc_pos = c->vc_pos - oldorigin + c->vc_origin;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return 1;
 }
@@ -1106,7 +1087,7 @@ sisusbcon_set_origin(struct vc_data *c)
        /* sisusb->lock is down */
 
        if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return 0;
        }
 
@@ -1116,7 +1097,7 @@ sisusbcon_set_origin(struct vc_data *c)
 
        sisusb->con_rolled_over = 0;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return 1;
 }
@@ -1133,7 +1114,7 @@ sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows)
 
        fh = sisusb->current_font_height;
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        /* We are quite unflexible as regards resizing. The vt code
         * handles sizes where the line length isn't equal the pitch
@@ -1167,7 +1148,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
 
        if ((slot != 0 && slot != 2) || !fh) {
                if (uplock)
-                       up(&sisusb->lock);
+                       mutex_unlock(&sisusb->lock);
                return -EINVAL;
        }
 
@@ -1327,7 +1308,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
        }
 
        if (uplock)
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
 
        if (dorecalc && c) {
                int i, rows = c->vc_scan_lines / fh;
@@ -1351,7 +1332,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
 
 font_op_error:
        if (uplock)
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
 
        return -EIO;
 }
@@ -1417,19 +1398,19 @@ sisusbcon_font_get(struct vc_data *c, struct console_font *font)
        font->charcount = 256;
 
        if (!font->data) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return 0;
        }
 
        if (!sisusb->font_backup) {
-               up(&sisusb->lock);
+               mutex_unlock(&sisusb->lock);
                return -ENODEV;
        }
 
        /* Copy 256 chars only, like vgacon */
        memcpy(font->data, sisusb->font_backup, 256 * 32);
 
-       up(&sisusb->lock);
+       mutex_unlock(&sisusb->lock);
 
        return 0;
 }
@@ -1486,7 +1467,7 @@ static int sisusbdummycon_dummy(void)
 
 #define SISUSBCONDUMMY (void *)sisusbdummycon_dummy
 
-const struct consw sisusb_dummy_con = {
+static const struct consw sisusb_dummy_con = {
        .owner =                THIS_MODULE,
        .con_startup =          sisusbdummycon_startup,
        .con_init =             sisusbdummycon_init,
@@ -1512,14 +1493,14 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 {
        int i, ret, minor = sisusb->minor;
 
-       down(&disconnect_sem);
+       mutex_lock(&disconnect_mutex);
 
-       down(&sisusb->lock);
+       mutex_lock(&sisusb->lock);
 
        /* Erm.. that should not happen */
        if (sisusb->haveconsole || !sisusb->SiS_Pr) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                return 1;
        }
 
@@ -1529,15 +1510,15 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
        if (first > last ||
            first > MAX_NR_CONSOLES ||
            last > MAX_NR_CONSOLES) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                return 1;
        }
 
        /* If gfxcore not initialized or no consoles given, quit graciously */
        if (!sisusb->gfxinit || first < 1 || last < 1) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                return 0;
        }
 
@@ -1547,8 +1528,8 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 
        /* Set up text mode (and upload  default font) */
        if (sisusb_reset_text_mode(sisusb, 1)) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                printk(KERN_ERR
                        "sisusbvga[%d]: Failed to set up text mode\n",
                        minor);
@@ -1571,16 +1552,16 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 
        /* Allocate screen buffer */
        if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
-               up(&sisusb->lock);
-               up(&disconnect_sem);
+               mutex_unlock(&sisusb->lock);
+               mutex_unlock(&disconnect_mutex);
                printk(KERN_ERR
                        "sisusbvga[%d]: Failed to allocate screen buffer\n",
                        minor);
                return 1;
        }
 
-       up(&sisusb->lock);
-       up(&disconnect_sem);
+       mutex_unlock(&sisusb->lock);
+       mutex_unlock(&disconnect_mutex);
 
        /* Now grab the desired console(s) */
        ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
index 044fa4482f9f471764d99feaa43f9e8af01dfcda..968f0d38cff769b87cfb46135fe5bff37bf0739d 100644 (file)
@@ -74,6 +74,7 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
 /*            HELPER: Get ModeID             */
 /*********************************************/
 
+#if 0
 unsigned short
 SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
 {
@@ -157,6 +158,7 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
 
        return ModeIndex;
 }
+#endif  /*  0  */
 
 /*********************************************/
 /*          HELPER: SetReg, GetReg           */
@@ -233,7 +235,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 /*        HELPER: Init Port Addresses        */
 /*********************************************/
 
-void
+static void
 SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 {
        SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
index 5b11577835c8d7d6a1fabe345bcd1126c4b63dd1..f05f83268af41df9ccce52a6d99e244d819b4cc1 100644 (file)
@@ -690,7 +690,7 @@ static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
    0x41}}   /* 0x54 */
 };
 
-static struct SiS_VCLKData SiSUSB_VCLKData[] =
+static const struct SiS_VCLKData SiSUSB_VCLKData[] =
 {
        { 0x1b,0xe1, 25}, /* 0x00 */
        { 0x4e,0xe4, 28}, /* 0x01 */
@@ -808,8 +808,8 @@ static struct SiS_VCLKData SiSUSB_VCLKData[] =
        { 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
 };
 
-void           SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr);
-unsigned short SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth);
+extern struct mutex disconnect_mutex;
+
 int            SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
 int            SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 
@@ -826,5 +826,19 @@ extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
 extern int     sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
                                        u8 idx, u8 myand);
 
+void sisusb_delete(struct kref *kref);
+int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
+                      u32 dest, int length, size_t *bytes_written);
+int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
+int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
+                        u8 *arg, int cmapsz, int ch512, int dorecalc,
+                        struct vc_data *c, int fh, int uplock);
+void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
+int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
+void sisusb_console_exit(struct sisusb_usb_data *sisusb);
+void sisusb_init_concode(void);
+
 #endif
 
index 94edd4726c4249cd18040b4f310c2805153b941d..f325ecb29a61f9e9722063db9601ccb89df4cba2 100644 (file)
@@ -161,7 +161,7 @@ struct SiS_Private
        const struct SiS_Ext            *SiS_EModeIDTable;
        const struct SiS_Ext2           *SiS_RefIndex;
        const struct SiS_CRT1Table      *SiS_CRT1Table;
-       struct SiS_VCLKData             *SiS_VCLKData;
+       const struct SiS_VCLKData       *SiS_VCLKData;
        const struct SiS_ModeResInfo    *SiS_ModeResInfo;
 };
 
index ccc5e8238bd889581b2b445cdb4b26108b5c6644..81ba14c73dc7b5b321408979043c3e2a0c428712 100644 (file)
@@ -802,7 +802,9 @@ error:
 
                                if (u == urb || !u->dev)
                                        continue;
+                               spin_unlock(&ctx->lock);
                                status = usb_unlink_urb (u);
+                               spin_lock(&ctx->lock);
                                switch (status) {
                                case -EINPROGRESS:
                                case -EBUSY:
@@ -1335,7 +1337,9 @@ struct iso_context {
        unsigned                pending;
        spinlock_t              lock;
        struct completion       done;
+       int                     submit_error;
        unsigned long           errors;
+       unsigned long           packet_count;
        struct usbtest_dev      *dev;
 };
 
@@ -1346,10 +1350,14 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs)
        spin_lock(&ctx->lock);
        ctx->count--;
 
+       ctx->packet_count += urb->number_of_packets;
        if (urb->error_count > 0)
                ctx->errors += urb->error_count;
+       else if (urb->status != 0)
+               ctx->errors += urb->number_of_packets;
 
-       if (urb->status == 0 && ctx->count > (ctx->pending - 1)) {
+       if (urb->status == 0 && ctx->count > (ctx->pending - 1)
+                       && !ctx->submit_error) {
                int status = usb_submit_urb (urb, GFP_ATOMIC);
                switch (status) {
                case 0:
@@ -1360,6 +1368,8 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs)
                                        status);
                        /* FALLTHROUGH */
                case -ENODEV:                   /* disconnected */
+               case -ESHUTDOWN:                /* endpoint disabled */
+                       ctx->submit_error = 1;
                        break;
                }
        }
@@ -1369,8 +1379,8 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs)
        if (ctx->pending == 0) {
                if (ctx->errors)
                        dev_dbg (&ctx->dev->intf->dev,
-                               "iso test, %lu errors\n",
-                               ctx->errors);
+                               "iso test, %lu errors out of %lu\n",
+                               ctx->errors, ctx->packet_count);
                complete (&ctx->done);
        }
 done:
@@ -1431,15 +1441,14 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
        struct usb_device       *udev;
        unsigned                i;
        unsigned long           packets = 0;
-       int                     status;
+       int                     status = 0;
        struct urb              *urbs[10];      /* FIXME no limit */
 
        if (param->sglen > 10)
                return -EDOM;
 
+       memset(&context, 0, sizeof context);
        context.count = param->iterations * param->sglen;
-       context.pending = param->sglen;
-       context.errors = 0;
        context.dev = dev;
        init_completion (&context.done);
        spin_lock_init (&context.lock);
@@ -1471,6 +1480,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
 
        spin_lock_irq (&context.lock);
        for (i = 0; i < param->sglen; i++) {
+               ++context.pending;
                status = usb_submit_urb (urbs [i], SLAB_ATOMIC);
                if (status < 0) {
                        ERROR (dev, "submit iso[%d], error %d\n", i, status);
@@ -1481,12 +1491,26 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
 
                        simple_free_urb (urbs [i]);
                        context.pending--;
+                       context.submit_error = 1;
+                       break;
                }
        }
        spin_unlock_irq (&context.lock);
 
        wait_for_completion (&context.done);
-       return 0;
+
+       /*
+        * Isochronous transfers are expected to fail sometimes.  As an
+        * arbitrary limit, we will report an error if any submissions
+        * fail or if the transfer failure rate is > 10%.
+        */
+       if (status != 0)
+               ;
+       else if (context.submit_error)
+               status = -EACCES;
+       else if (context.errors > context.packet_count / 10)
+               status = -EIO;
+       return status;
 
 fail:
        for (i = 0; i < param->sglen; i++) {
index 0a1367b760a00947e72d1b539d3dc9f6e32cd3f5..ddcfc01e77a022918940d725986ff0061591f6cb 100644 (file)
 #include <linux/usb.h> /* Only needed for declarations in usb_mon.h */
 #include "usb_mon.h"
 
-#ifdef __i386__                /* CONFIG_ARCH_I386 does not exit */
+/*
+ * PC-compatibles, are, fortunately, sufficiently cache-coherent for this.
+ */
+#if defined(__i386__) || defined(__x86_64__) /* CONFIG_ARCH_I386 doesn't exit */
 #define MON_HAS_UNMAP 1
 
 #define phys_to_page(phys)     pfn_to_page((phys) >> PAGE_SHIFT)
index 6ecc273022117351f9d155e3d16ab6d3a8a7ab34..275a66f8305878b2f435506e675a851454b586af 100644 (file)
@@ -97,6 +97,7 @@ static void mon_submit(struct usb_bus *ubus, struct urb *urb)
        if (mbus->nreaders == 0)
                goto out_locked;
 
+       mbus->cnt_events++;
        list_for_each (pos, &mbus->r_list) {
                r = list_entry(pos, struct mon_reader, r_link);
                r->rnf_submit(r->r_data, urb);
@@ -113,20 +114,32 @@ out_unlocked:
 
 /*
  */
-static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int err)
+static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
 {
        struct mon_bus *mbus;
+       unsigned long flags;
+       struct list_head *pos;
+       struct mon_reader *r;
 
        mbus = ubus->mon_bus;
        if (mbus == NULL)
                goto out_unlocked;
 
-       /*
-        * XXX Capture the error code and the 'E' event.
-        */
+       spin_lock_irqsave(&mbus->lock, flags);
+       if (mbus->nreaders == 0)
+               goto out_locked;
 
+       mbus->cnt_events++;
+       list_for_each (pos, &mbus->r_list) {
+               r = list_entry(pos, struct mon_reader, r_link);
+               r->rnf_error(r->r_data, urb, error);
+       }
+
+       spin_unlock_irqrestore(&mbus->lock, flags);
        return;
 
+out_locked:
+       spin_unlock_irqrestore(&mbus->lock, flags);
 out_unlocked:
        return;
 }
@@ -152,6 +165,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
        }
 
        spin_lock_irqsave(&mbus->lock, flags);
+       mbus->cnt_events++;
        list_for_each (pos, &mbus->r_list) {
                r = list_entry(pos, struct mon_reader, r_link);
                r->rnf_complete(r->r_data, urb);
@@ -163,7 +177,6 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
 
 /*
  * Stop monitoring.
- * Obviously this must be well locked, so no need to play with mb's.
  */
 static void mon_stop(struct mon_bus *mbus)
 {
index 6e4b165d070ad6cfac00ab11c30ad9d206d8a709..1fe01d994a793f79ec801a663a8ddb1eec54a345 100644 (file)
@@ -31,8 +31,8 @@ static int mon_stat_open(struct inode *inode, struct file *file)
        mbus = inode->u.generic_ip;
 
        sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
-           "nreaders %d text_lost %u\n",
-           mbus->nreaders, mbus->cnt_text_lost);
+           "nreaders %d events %u text_lost %u\n",
+           mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost);
 
        file->private_data = sp;
        return 0;
index ac043ec2b8dcece7b124b8917bd21ab69a1c70ad..e02c1a30c4cd4d65d852ce010d522c05e594c256 100644 (file)
 
 /*
  * This limit exists to prevent OOMs when the user process stops reading.
+ * If usbmon were available to unprivileged processes, it might be open
+ * to a local DoS. But we have to keep to root in order to prevent
+ * password sniffing from HID devices.
  */
-#define EVENT_MAX  25
+#define EVENT_MAX  (2*PAGE_SIZE / sizeof(struct mon_event_text))
 
-#define PRINTF_DFL  130
+#define PRINTF_DFL  160
 
 struct mon_event_text {
        struct list_head e_link;
@@ -111,7 +114,7 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
         * number of corner cases, but it seems that the following is
         * more or less safe.
         *
-        * We do not even try to look transfer_buffer, because it can
+        * We do not even try to look at transfer_buffer, because it can
         * contain non-NULL garbage in case the upper level promised to
         * set DMA for the HCD.
         */
@@ -179,6 +182,32 @@ static void mon_text_complete(void *data, struct urb *urb)
        mon_text_event(rp, urb, 'C');
 }
 
+static void mon_text_error(void *data, struct urb *urb, int error)
+{
+       struct mon_reader_text *rp = data;
+       struct mon_event_text *ep;
+
+       if (rp->nevents >= EVENT_MAX ||
+           (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) {
+               rp->r.m_bus->cnt_text_lost++;
+               return;
+       }
+
+       ep->type = 'E';
+       ep->pipe = urb->pipe;
+       ep->id = (unsigned long) urb;
+       ep->tstamp = 0;
+       ep->length = 0;
+       ep->status = error;
+
+       ep->setup_flag = '-';
+       ep->data_flag = 'E';
+
+       rp->nevents++;
+       list_add_tail(&ep->e_link, &rp->e_list);
+       wake_up(&rp->wait);
+}
+
 /*
  * Fetch next event from the circular buffer.
  */
@@ -232,6 +261,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
        rp->r.m_bus = mbus;
        rp->r.r_data = rp;
        rp->r.rnf_submit = mon_text_submit;
+       rp->r.rnf_error = mon_text_error;
        rp->r.rnf_complete = mon_text_complete;
 
        snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum,
index 8e0613c350ccdd196008de7a8f16a4c02e26bb7e..33678c24ebeed5713b06a9eb1fd32d3283effc67 100644 (file)
@@ -27,6 +27,7 @@ struct mon_bus {
        struct kref ref;                /* Under mon_lock */
 
        /* Stats */
+       unsigned int cnt_events;
        unsigned int cnt_text_lost;
 };
 
@@ -39,6 +40,7 @@ struct mon_reader {
        void *r_data;           /* Use container_of instead? */
 
        void (*rnf_submit)(void *data, struct urb *urb);
+       void (*rnf_error)(void *data, struct urb *urb, int error);
        void (*rnf_complete)(void *data, struct urb *urb);
 };
 
index 12b599a0b53989d69233734c956865eeab006d70..37111acec8756a3b013bfe002bc395d9f72e2ece 100644 (file)
@@ -911,6 +911,10 @@ static const struct usb_device_id  products [] = {
        // ASIX AX88772 10/100
         USB_DEVICE (0x0b95, 0x7720),
         .driver_info = (unsigned long) &ax88772_info,
+}, {
+       // ASIX AX88178 10/100/1000
+       USB_DEVICE (0x0b95, 0x1780),
+       .driver_info = (unsigned long) &ax88772_info,
 }, {
        // Linksys USB200M Rev 2
        USB_DEVICE (0x13b1, 0x0018),
index 63f1f3ba8e0b3576f2cee0918f369c433f9d8dc6..efd195b5912c6bdab30a27f2fa86158a2a9d1ab2 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
-#include <linux/usb_cdc.h>
+#include <linux/usb/cdc.h>
 
 #include "usbnet.h"
 
@@ -455,6 +455,18 @@ static const struct usb_device_id  products [] = {
        .driver_info            = 0,
 },
 
+/* Olympus has some models with a Zaurus-compatible option.
+ * R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
+ */
+{
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x07B4,
+       .idProduct              = 0x0F02,       /* R-1000 */
+       ZAURUS_MASTER_INTERFACE,
+       .driver_info            = 0,
+},
+
 /*
  * WHITELIST!!!
  *
index 7683926a1b6f19c5fae68caa07a6727691acfc17..ab21f960d255f250c01f43912744103ab73cd03f 100644 (file)
@@ -163,6 +163,8 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
 
        /* using ATOMIC, we'd never wake up if we slept */
        if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
+               if (ret == -ENODEV)
+                       netif_device_detach(pegasus->net);
                if (netif_msg_drv(pegasus))
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
                                        __FUNCTION__, ret);
@@ -217,6 +219,8 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
        set_current_state(TASK_UNINTERRUPTIBLE);
 
        if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
+               if (ret == -ENODEV)
+                       netif_device_detach(pegasus->net);
                if (netif_msg_drv(pegasus))
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
                                        __FUNCTION__, ret);
@@ -268,6 +272,8 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
        set_current_state(TASK_UNINTERRUPTIBLE);
 
        if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
+               if (ret == -ENODEV)
+                       netif_device_detach(pegasus->net);
                if (netif_msg_drv(pegasus))
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
                                        __FUNCTION__, ret);
@@ -298,10 +304,13 @@ static int update_eth_regs_async(pegasus_t * pegasus)
                             (char *) &pegasus->dr,
                             pegasus->eth_regs, 3, ctrl_callback, pegasus);
 
-       if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC)))
+       if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
+               if (ret == -ENODEV)
+                       netif_device_detach(pegasus->net);
                if (netif_msg_drv(pegasus))
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
                                        __FUNCTION__, ret);
+       }
 
        return ret;
 }
@@ -692,7 +701,10 @@ goon:
                          usb_rcvbulkpipe(pegasus->usb, 1),
                          pegasus->rx_skb->data, PEGASUS_MTU + 8,
                          read_bulk_callback, pegasus);
-       if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) {
+       rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC);
+       if (rx_status == -ENODEV)
+               netif_device_detach(pegasus->net);
+       else if (rx_status) {
                pegasus->flags |= PEGASUS_RX_URB_FAIL;
                goto tl_sched;
        } else {
@@ -709,6 +721,7 @@ static void rx_fixup(unsigned long data)
 {
        pegasus_t *pegasus;
        unsigned long flags;
+       int status;
 
        pegasus = (pegasus_t *) data;
        if (pegasus->flags & PEGASUS_UNPLUG)
@@ -734,7 +747,10 @@ static void rx_fixup(unsigned long data)
                          pegasus->rx_skb->data, PEGASUS_MTU + 8,
                          read_bulk_callback, pegasus);
 try_again:
-       if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) {
+       status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC);
+       if (status == -ENODEV)
+               netif_device_detach(pegasus->net);
+       else if (status) {
                pegasus->flags |= PEGASUS_RX_URB_FAIL;
                tasklet_schedule(&pegasus->rx_tl);
        } else {
@@ -836,6 +852,8 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)
        }
 
        status = usb_submit_urb(urb, SLAB_ATOMIC);
+       if (status == -ENODEV)
+               netif_device_detach(pegasus->net);
        if (status && netif_msg_timer(pegasus))
                printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n",
                                net->name, status);
@@ -874,6 +892,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
                        /* cleanup should already have been scheduled */
                        break;
                case -ENODEV:           /* disconnect() upcoming */
+                       netif_device_detach(pegasus->net);
                        break;
                default:
                        pegasus->stats.tx_errors++;
@@ -999,6 +1018,8 @@ static int pegasus_open(struct net_device *net)
                          pegasus->rx_skb->data, PEGASUS_MTU + 8,
                          read_bulk_callback, pegasus);
        if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) {
+               if (res == -ENODEV)
+                       netif_device_detach(pegasus->net);
                if (netif_msg_ifup(pegasus))
                        pr_debug("%s: failed rx_urb, %d", net->name, res);
                goto exit;
@@ -1009,6 +1030,8 @@ static int pegasus_open(struct net_device *net)
                         pegasus->intr_buff, sizeof (pegasus->intr_buff),
                         intr_callback, pegasus, pegasus->intr_interval);
        if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
+               if (res == -ENODEV)
+                       netif_device_detach(pegasus->net);
                if (netif_msg_ifup(pegasus))
                        pr_debug("%s: failed intr_urb, %d\n", net->name, res);
                usb_kill_urb(pegasus->rx_urb);
index 94ddfe16fdda9237454525b745ba3f0b3e8c76ba..f551546d7521834872cf5e0db502238449d2b7a1 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
-#include <linux/usb_cdc.h>
+#include <linux/usb/cdc.h>
 
 #include "usbnet.h"
 
index f7ac9d6b985687a197994e2211c9ca30cb1649e3..813e470d0600435d058f14f471118817850b46c4 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/mii.h>
 #include <linux/crc32.h>
 #include <linux/usb.h>
-#include <linux/usb_cdc.h>
+#include <linux/usb/cdc.h>
 
 #include "usbnet.h"
 
@@ -109,7 +109,7 @@ static const struct driver_info     zaurus_sl5x00_info = {
        .check_connect = always_connected,
        .bind =         zaurus_bind,
        .unbind =       usbnet_cdc_unbind,
-       .tx_fixup =     zaurus_tx_fixup,
+       .tx_fixup =     zaurus_tx_fixup,
 };
 #define        ZAURUS_STRONGARM_INFO   ((unsigned long)&zaurus_sl5x00_info)
 
@@ -119,7 +119,7 @@ static const struct driver_info     zaurus_pxa_info = {
        .check_connect = always_connected,
        .bind =         zaurus_bind,
        .unbind =       usbnet_cdc_unbind,
-       .tx_fixup =     zaurus_tx_fixup,
+       .tx_fixup =     zaurus_tx_fixup,
 };
 #define        ZAURUS_PXA_INFO         ((unsigned long)&zaurus_pxa_info)
 
@@ -129,7 +129,7 @@ static const struct driver_info     olympus_mxl_info = {
        .check_connect = always_connected,
        .bind =         zaurus_bind,
        .unbind =       usbnet_cdc_unbind,
-       .tx_fixup =     zaurus_tx_fixup,
+       .tx_fixup =     zaurus_tx_fixup,
 };
 #define        OLYMPUS_MXL_INFO        ((unsigned long)&olympus_mxl_info)
 
@@ -228,6 +228,11 @@ bad_detail:
                                                detail->bDetailData[2]);
                                goto bad_desc;
                        }
+
+                       /* same extra framing as for non-BLAN mode */
+                       dev->net->hard_header_len += 6;
+                       dev->rx_urb_size = dev->net->hard_header_len
+                                       + dev->net->mtu;
                        break;
                }
 next_desc:
@@ -258,7 +263,7 @@ static const struct driver_info     bogus_mdlm_info = {
        .description =  "pseudo-MDLM (BLAN) device",
        .flags =        FLAG_FRAMING_Z,
        .check_connect = always_connected,
-       .tx_fixup =     zaurus_tx_fixup,
+       .tx_fixup =     zaurus_tx_fixup,
        .bind =         blan_mdlm_bind,
 };
 
@@ -367,13 +372,13 @@ static struct usb_driver zaurus_driver = {
 
 static int __init zaurus_init(void)
 {
-       return usb_register(&zaurus_driver);
+       return usb_register(&zaurus_driver);
 }
 module_init(zaurus_init);
 
 static void __exit zaurus_exit(void)
 {
-       usb_deregister(&zaurus_driver);
+       usb_deregister(&zaurus_driver);
 }
 module_exit(zaurus_exit);
 
index 5c60be521561a5fdeed21d5bd4df5a37b5a9ee9b..8bd44fda5eafb18a16dab40885cefa4ae900385c 100644 (file)
@@ -417,7 +417,7 @@ config USB_SERIAL_MCT_U232
          Magic Control Technology Corp. (U232 is one of the model numbers).
 
          This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB
-         BAY devices.
+         BAY, Belkin F5U109, and Belkin F5U409 devices.
 
          To compile this driver as a module, choose M here: the
          module will be called mct_u232.
@@ -491,16 +491,22 @@ config USB_SERIAL_XIRCOM
          module will be called keyspan_pda.
 
 config USB_SERIAL_OPTION
-       tristate "USB Option PCMCIA serial driver"
-       depends on USB_SERIAL && USB_OHCI_HCD && PCCARD
+       tristate "USB driver for GSM modems"
+       depends on USB_SERIAL
        help
-         Say Y here if you want to use an Option card. This is a
-         GSM card, controlled by three serial ports which are connected
-         via an OHCI adapter located on a PC card.
+         Say Y here if you have an "Option" GSM PCMCIA card
+         (or an OEM version: branded Huawei, Audiovox, or Novatel).
+
+         These cards feature a built-in OHCI-USB adapter and an
+         internally-connected GSM modem. The USB bus is not
+         accessible externally.
 
          To compile this driver as a module, choose M here: the
          module will be called option.
 
+         If this driver doesn't recognize your device,
+         it might be accessible via the FTDI_SIO driver.
+
 config USB_SERIAL_OMNINET
        tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)"
        depends on USB_SERIAL && EXPERIMENTAL
index 694b205f9b736e90f42e995b9d90de1a2d5bc72a..94b9ba0ff8755f479192573d7971af8462cc8ecd 100644 (file)
 #include "usb-serial.h"
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
        { USB_DEVICE(0xf3d, 0x0112) },  /* AirPrime CDMA Wireless PC Card */
        { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
        { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
+       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
index 8023bb7279b123f52fbe400032a30d611dfe588e..f3404e10afb4a3abb05bfeecc637883d68a3d3d2 100644 (file)
@@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
        struct usb_serial *serial;
        int retval = -ENODEV;
 
-       if (!port)
+       if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
                return;
        serial = port->serial;
 
@@ -213,17 +213,38 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun
 
        if (!port->open_count) {
                dbg ("%s - port not opened", __FUNCTION__);
-               goto exit;
+               return;
        }
 
-       /* pass on to the driver specific version of this function if it is available */
-       if (serial->type->write)
-               retval = serial->type->write(port, buf, count);
-       else
-               retval = usb_serial_generic_write(port, buf, count);
-
-exit:
-       dbg("%s - return value (if we had one): %d", __FUNCTION__, retval);
+       while (count) {
+               unsigned int i;
+               unsigned int lf;
+               /* search for LF so we can insert CR if necessary */
+               for (i=0, lf=0 ; i < count ; i++) {
+                       if (*(buf + i) == 10) {
+                               lf = 1;
+                               i++;
+                               break;
+                       }
+               }
+               /* pass on to the driver specific version of this function if it is available */
+               if (serial->type->write)
+                       retval = serial->type->write(port, buf, i);
+               else
+                       retval = usb_serial_generic_write(port, buf, i);
+               dbg("%s - return value : %d", __FUNCTION__, retval);
+               if (lf) {
+                       /* append CR after LF */
+                       unsigned char cr = 13;
+                       if (serial->type->write)
+                               retval = serial->type->write(port, &cr, 1);
+                       else
+                               retval = usb_serial_generic_write(port, &cr, 1);
+                       dbg("%s - return value : %d", __FUNCTION__, retval);
+               }
+               buf += i;
+               count -= i;
+       }
 }
 
 static struct console usbcons = {
@@ -234,6 +255,14 @@ static struct console usbcons = {
        .index =        -1,
 };
 
+void usb_serial_console_disconnect(struct usb_serial *serial)
+{
+       if (serial && serial->port && serial->port[0] && serial->port[0] == usbcons_info.port) {
+               usb_serial_console_exit();
+               usb_serial_put(serial);
+       }
+}
+
 void usb_serial_console_init (int serial_debug, int minor)
 {
        debug = serial_debug;
@@ -259,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor)
 
 void usb_serial_console_exit (void)
 {
-       unregister_console(&usbcons);
+       if (usbcons_info.port) {
+               unregister_console(&usbcons);
+               if (usbcons_info.port->open_count)
+                       usbcons_info.port->open_count--;
+               usbcons_info.port = NULL;
+       }
 }
 
index e0c2acdb3f06e00ff253f1cd937b742f1e7a7f66..f8c0cb287736998ab767abd1627fa6f8ace34de5 100644 (file)
@@ -59,6 +59,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
        { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
+       { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
        { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
        { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
        { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
index 2357b1d102d7e5fef562be87c47ca703d35d678c..1fd5c5a9f2efd45a38c9609f99642745dccf419c 100644 (file)
@@ -469,7 +469,7 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
 
 exit:
        spin_unlock(&priv->lock);
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 static int __init cyberjack_init (void)
index 7212fbe3b6f28506b037475ed9be5bcae38f7d29..5de76efe1b37f986fb3f6623717dc6cccb8d4c67 100644 (file)
@@ -824,7 +824,7 @@ send:
        priv->bytes_out += count; /* do not count the line control and size bytes */
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 } /* cypress_send */
 
 
index 63f7c78a1152d05924711628be6c2e93b70ef555..afca1eae5fb52499dc20b9dcd1d4b9da48fc6592 100644 (file)
@@ -335,7 +335,7 @@ static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
                return;
        }
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 
index 986d7622273d319e1ae4178aada87170fe246918..b2bfea7c815aa3e9d7fefa1831877386a4b6f0d8 100644 (file)
@@ -500,6 +500,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) },
        { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -1261,7 +1262,6 @@ static void ftdi_shutdown (struct usb_serial *serial)
 
 static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_open */
-       struct termios tmp_termios;
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
@@ -1271,8 +1271,8 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
 
        dbg("%s", __FUNCTION__);
 
-
-       port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       if (port->tty)
+               port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        /* No error checking for this (will get errors later anyway) */
        /* See ftdi_sio.h for description of what is reset */
@@ -1286,7 +1286,8 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
           This is same behaviour as serial.c/rs_open() - Kuba */
 
        /* ftdi_set_termios  will send usb control messages */
-       ftdi_set_termios(port, &tmp_termios);
+       if (port->tty)
+               ftdi_set_termios(port, NULL);
 
        /* FIXME: Flow control might be enabled, so it should be checked -
           we have no control of defaults! */
@@ -1472,7 +1473,7 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
                return;
        }
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 } /* ftdi_write_bulk_callback */
 
 
@@ -1867,7 +1868,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
                        err("%s urb failed to set baudrate", __FUNCTION__);
                }
                /* Ensure RTS and DTR are raised when baudrate changed from 0 */
-               if ((old_termios->c_cflag & CBAUD) == B0) {
+               if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) {
                        set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
                }
        }
index d69a917e768f2e445851b7fea27442c3e023e48d..6ab2ac845bd7a861c7d456ab94607160fe692030 100644 (file)
  */
 #define FTDI_ACG_HFDUAL_PID            0xDD20  /* HF Dual ISO Reader (RFID) */
 
+/*
+ * Yost Engineering, Inc. products (www.yostengineering.com).
+ * PID 0xE050 submitted by Aaron Prose.
+ */
+#define FTDI_YEI_SERVOCENTER31_PID     0xE050  /* YEI ServoCenter3.1 USB */
+
 /* Commands */
 #define FTDI_SIO_RESET                 0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL    1 /* Set the modem control register */
index 5ec9bf5bac8dc635608dd195db4bc51277174b83..04767759cf8a8e5190a93b232d4fca7c76ba727c 100644 (file)
@@ -1012,7 +1012,7 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
                garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
        }
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 
index c62cc2876519629a6bd39e8b6284b84a51d201ab..07a478c59fb2bd43b3a31df788430dc5b696ff6c 100644 (file)
@@ -299,9 +299,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re
                return;
        }
 
-       usb_serial_port_softint((void *)port);
-
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
 
index b606c596810283a292c96df327f9f8d1f1b12b94..b85d2156dfdc49c3fa211b0efd50a61b8ed497fa 100644 (file)
@@ -142,7 +142,7 @@ struct edgeport_port {
 
 /* This structure holds all of the individual device information */
 struct edgeport_serial {
-       char                    name[MAX_NAME_LEN+1];           /* string name of this device */
+       char                    name[MAX_NAME_LEN+2];           /* string name of this device */
 
        struct edge_manuf_descriptor    manuf_descriptor;       /* the manufacturer descriptor */
        struct edge_boot_descriptor     boot_descriptor;        /* the boot firmware descriptor */
@@ -270,7 +270,7 @@ static void get_manufacturing_desc  (struct edgeport_serial *edge_serial);
 static void get_boot_desc              (struct edgeport_serial *edge_serial);
 static void load_application_firmware  (struct edgeport_serial *edge_serial);
 
-static void unicode_to_ascii           (char *string, __le16 *unicode, int unicode_size);
+static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size);
 
 
 // ************************************************************************
@@ -373,7 +373,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
  *  Get string descriptor from device                                  *
  *                                                                     *
  ************************************************************************/
-static int get_string (struct usb_device *dev, int Id, char *string)
+static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
 {
        struct usb_string_descriptor StringDesc;
        struct usb_string_descriptor *pStringDesc;
@@ -395,7 +395,7 @@ static int get_string (struct usb_device *dev, int Id, char *string)
                return 0;
        }
 
-       unicode_to_ascii(string,  pStringDesc->wData,     pStringDesc->bLength/2-1);
+       unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
 
        kfree(pStringDesc);
        return strlen(string);
@@ -2564,16 +2564,20 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
  *     ASCII range, but it's only for debugging...
  *     NOTE: expects the unicode in LE format
  ****************************************************************************/
-static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size)
+static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size)
 {
        int i;
 
-       if (unicode_size <= 0)
+       if (buflen <= 0)        /* never happens, but... */
                return;
+       --buflen;               /* space for nul */
 
-       for (i = 0; i < unicode_size; ++i)
+       for (i = 0; i < unicode_size; i++) {
+               if (i >= buflen)
+                       break;
                string[i] = (char)(le16_to_cpu(unicode[i]));
-       string[unicode_size] = 0x00;
+       }
+       string[i] = 0x00;
 }
 
 
@@ -2603,11 +2607,17 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial)
                dbg("  BoardRev:       %d", edge_serial->manuf_descriptor.BoardRev);
                dbg("  NumPorts:       %d", edge_serial->manuf_descriptor.NumPorts);
                dbg("  DescDate:       %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900);
-               unicode_to_ascii (string, edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2-1);
+               unicode_to_ascii(string, sizeof(string),
+                   edge_serial->manuf_descriptor.SerialNumber,
+                   edge_serial->manuf_descriptor.SerNumLength/2);
                dbg("  SerialNumber: %s", string);
-               unicode_to_ascii (string, edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2-1);
+               unicode_to_ascii(string, sizeof(string),
+                   edge_serial->manuf_descriptor.AssemblyNumber,
+                   edge_serial->manuf_descriptor.AssemblyNumLength/2);
                dbg("  AssemblyNumber: %s", string);
-               unicode_to_ascii (string, edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2-1);
+               unicode_to_ascii(string, sizeof(string),
+                   edge_serial->manuf_descriptor.OemAssyNumber,
+                   edge_serial->manuf_descriptor.OemAssyNumLength/2);
                dbg("  OemAssyNumber:  %s", string);
                dbg("  UartType:       %d", edge_serial->manuf_descriptor.UartType);
                dbg("  IonPid:         %d", edge_serial->manuf_descriptor.IonPid);
@@ -2720,7 +2730,7 @@ static int edge_startup (struct usb_serial *serial)
        struct edgeport_serial *edge_serial;
        struct edgeport_port *edge_port;
        struct usb_device *dev;
-       int i;
+       int i, j;
 
        dev = serial->dev;
 
@@ -2735,11 +2745,11 @@ static int edge_startup (struct usb_serial *serial)
        usb_set_serial_data(serial, edge_serial);
 
        /* get the name for the device from the device */
-       if ( (i = get_string(dev, dev->descriptor.iManufacturer, &edge_serial->name[0])) != 0) {
-               edge_serial->name[i-1] = ' ';
-       }
-
-       get_string(dev, dev->descriptor.iProduct, &edge_serial->name[i]);
+       i = get_string(dev, dev->descriptor.iManufacturer,
+           &edge_serial->name[0], MAX_NAME_LEN+1);
+       edge_serial->name[i++] = ' ';
+       get_string(dev, dev->descriptor.iProduct,
+           &edge_serial->name[i], MAX_NAME_LEN+2 - i);
 
        dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
@@ -2784,6 +2794,10 @@ static int edge_startup (struct usb_serial *serial)
                edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
                if (edge_port == NULL) {
                        dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
+                       for (j = 0; j < i; ++j) {
+                               kfree (usb_get_serial_port_data(serial->port[j]));
+                               usb_set_serial_port_data(serial->port[j],  NULL);
+                       }
                        usb_set_serial_data(serial, NULL);
                        kfree(edge_serial);
                        return -ENOMEM;
index 9a5c979895629c727fdef8d377261b30efa21944..9da6d2a8f2b0c692a03186a6a2110ef40419b0e4 100644 (file)
@@ -870,7 +870,7 @@ static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
                spin_unlock_irqrestore(&write_list_lock, flags);
        }
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 static int ipaq_write_room(struct usb_serial_port *port)
index e760a70242c1ccace3664f1b2e46d72e67bb6386..a4a0bfeaab00ba88a4f31d35da5dd4d5cb566c56 100644 (file)
@@ -376,7 +376,7 @@ static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
        if (urb->status)
                dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int count)
index 426182ddc42a871d758ae8fc400f460138fd38f5..9432c73022758435fd9dbfaf1c374aee31079bbf 100644 (file)
@@ -408,7 +408,7 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
                urb->actual_length,
                urb->transfer_buffer);
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
index 052b735c4fbddd20daae7b80a6ad65768894ad31..2cf6ade704e41b77a267eba82c4250100a54786e 100644 (file)
@@ -481,7 +481,7 @@ static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs)
        dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]); 
 
        if (port->open_count)
-               schedule_work(&port->work);
+               usb_serial_port_softint(port);
 }
 
 static void    usa26_inack_callback(struct urb *urb, struct pt_regs *regs)
index 78335a5f77430e18a1d97e7b22e177f79ee07147..65d79f630fa4b8012435d5c6e6700810f33dd011 100644 (file)
@@ -569,8 +569,7 @@ static void klsi_105_write_bulk_callback ( struct urb *urb, struct pt_regs *regs
                return;
        }
 
-       /* from generic_write_bulk_callback */
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 } /* klsi_105_write_bulk_completion_callback */
 
 
index 238033a87092fc841c7c6ac225ff921ec381139a..6dcdb5f598b88b4ae211f9a0b1590d546be7a9ad 100644 (file)
@@ -320,7 +320,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
                return;
        }
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 
index 5cf2b80add7aa01ede3b1a588dc5c002d6dbccb8..b0861b61bba78e36920e8913e15fcd3b4733658d 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Option Card (PCMCIA to) USB to Serial Driver
+  USB Driver for GSM modems
 
   Copyright (C) 2005  Matthias Urlichs <smurf@smurf.noris.de>
 
   2005-09-10  v0.4.3 added HUAWEI E600 card and Audiovox AirCard
   2005-09-20  v0.4.4 increased recv buffer size: the card sometimes
                      wants to send >2000 bytes.
-  2006-04-10  v0.4.2 fixed two array overrun errors :-/
+  2006-04-10  v0.5   fixed two array overrun errors :-/
+  2006-04-21  v0.5.1 added support for Sierra Wireless MC8755
+  2006-05-15  v0.6   re-enable multi-port support
+  2006-06-01  v0.6.1 add COBRA
+  2006-06-01  v0.6.2 add backwards-compatibility stuff
+  2006-06-01  v0.6.3 add Novatel Wireless
+  2006-06-01  v0.7   Option => GSM
 
   Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
 
+  This driver exists because the "normal" serial driver doesn't work too well
+  with GSM modems. Issues:
+  - data loss -- one single Receive URB is not nearly enough
+  - nonstandard flow (Option devices) and multiplex (Sierra) control
+  - controlling the baud rate doesn't make sense
+
+  This driver is named "option" because the most common device it's
+  used for is a PC-Card (with an internal OHCI-USB interface, behind
+  which the GSM interface sits), made by Option Inc.
+
+  Some of the "one port" devices actually exhibit multiple USB instances
+  on the USB bus. This is not a bug, these ports are used for different
+  device features.
 */
 
-#define DRIVER_VERSION "v0.4"
+#define DRIVER_VERSION "v0.7.0"
 #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
-#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver"
+#define DRIVER_DESC "USB Driver for GSM modems"
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -74,22 +93,45 @@ static int  option_tiocmset(struct usb_serial_port *port, struct file *file,
 static int  option_send_setup(struct usb_serial_port *port);
 
 /* Vendor and product IDs */
-#define OPTION_VENDOR_ID                       0x0AF0
-#define HUAWEI_VENDOR_ID                       0x12D1
-#define AUDIOVOX_VENDOR_ID                     0x0F3D
-
-#define OPTION_PRODUCT_OLD             0x5000
-#define OPTION_PRODUCT_FUSION  0x6000
-#define OPTION_PRODUCT_FUSION2 0x6300
-#define HUAWEI_PRODUCT_E600     0x1001
-#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
+#define OPTION_VENDOR_ID                0x0AF0
+#define HUAWEI_VENDOR_ID                0x12D1
+#define AUDIOVOX_VENDOR_ID              0x0F3D
+#define SIERRAWIRELESS_VENDOR_ID        0x1199
+#define NOVATELWIRELESS_VENDOR_ID       0x1410
+
+#define OPTION_PRODUCT_OLD              0x5000
+#define OPTION_PRODUCT_FUSION           0x6000
+#define OPTION_PRODUCT_FUSION2          0x6300
+#define OPTION_PRODUCT_COBRA            0x6500
+#define HUAWEI_PRODUCT_E600             0x1001
+#define AUDIOVOX_PRODUCT_AIRCARD        0x0112
+#define SIERRAWIRELESS_PRODUCT_MC8755   0x6802
+#define NOVATELWIRELESS_PRODUCT_U740    0x1400
 
 static struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
        { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
        { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
+       { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
+       { } /* Terminating entry */
+};
+
+static struct usb_device_id option_ids1[] = {
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
+       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
+       { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
+       { } /* Terminating entry */
+};
+static struct usb_device_id option_ids3[] = {
+       { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
        { } /* Terminating entry */
 };
 
@@ -111,12 +153,39 @@ static struct usb_serial_driver option_3port_device = {
                .owner =        THIS_MODULE,
                .name =         "option",
        },
-       .description       = "Option 3G data card",
-       .id_table          = option_ids,
+       .description       = "GSM modem (3-port)",
+       .id_table          = option_ids3,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = NUM_DONT_CARE,
        .num_bulk_out      = NUM_DONT_CARE,
-       .num_ports         = 1, /* 3, but the card reports its ports separately */
+       .num_ports         = 3,
+       .open              = option_open,
+       .close             = option_close,
+       .write             = option_write,
+       .write_room        = option_write_room,
+       .chars_in_buffer   = option_chars_in_buffer,
+       .throttle          = option_rx_throttle,
+       .unthrottle        = option_rx_unthrottle,
+       .set_termios       = option_set_termios,
+       .break_ctl         = option_break_ctl,
+       .tiocmget          = option_tiocmget,
+       .tiocmset          = option_tiocmset,
+       .attach            = option_startup,
+       .shutdown          = option_shutdown,
+       .read_int_callback = option_instat_callback,
+};
+
+static struct usb_serial_driver option_1port_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "option",
+       },
+       .description       = "GSM modem (1-port)",
+       .id_table          = option_ids1,
+       .num_interrupt_in  = NUM_DONT_CARE,
+       .num_bulk_in       = NUM_DONT_CARE,
+       .num_bulk_out      = NUM_DONT_CARE,
+       .num_ports         = 1,
        .open              = option_open,
        .close             = option_close,
        .write             = option_write,
@@ -170,6 +239,9 @@ struct option_port_private {
 static int __init option_init(void)
 {
        int retval;
+       retval = usb_serial_register(&option_1port_device);
+       if (retval)
+               goto failed_1port_device_register;
        retval = usb_serial_register(&option_3port_device);
        if (retval)
                goto failed_3port_device_register;
@@ -184,6 +256,8 @@ static int __init option_init(void)
 failed_driver_register:
        usb_serial_deregister (&option_3port_device);
 failed_3port_device_register:
+       usb_serial_deregister (&option_1port_device);
+failed_1port_device_register:
        return retval;
 }
 
@@ -191,6 +265,7 @@ static void __exit option_exit(void)
 {
        usb_deregister (&option_driver);
        usb_serial_deregister (&option_3port_device);
+       usb_serial_deregister (&option_1port_device);
 }
 
 module_init(option_init);
@@ -365,8 +440,7 @@ static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
 
        port = (struct usb_serial_port *) urb->context;
 
-       if (port->open_count)
-               schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 static void option_instat_callback(struct urb *urb, struct pt_regs *regs)
@@ -573,27 +647,30 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
 /* Setup urbs */
 static void option_setup_urbs(struct usb_serial *serial)
 {
-       int j;
+       int i,j;
        struct usb_serial_port *port;
        struct option_port_private *portdata;
 
        dbg("%s", __FUNCTION__);
 
-       port = serial->port[0];
-       portdata = usb_get_serial_port_data(port);
+
+       for (i = 0; i < serial->num_ports; i++) {
+               port = serial->port[i];
+               portdata = usb_get_serial_port_data(port);
 
        /* Do indat endpoints first */
-       for (j = 0; j < N_IN_URB; ++j) {
-               portdata->in_urbs[j] = option_setup_urb (serial,
-                  port->bulk_in_endpointAddress, USB_DIR_IN, port,
-                  portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
-       }
+               for (j = 0; j < N_IN_URB; ++j) {
+                       portdata->in_urbs[j] = option_setup_urb (serial,
+                       port->bulk_in_endpointAddress, USB_DIR_IN, port,
+                       portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
+               }
 
-       /* outdat endpoints */
-       for (j = 0; j < N_OUT_URB; ++j) {
-               portdata->out_urbs[j] = option_setup_urb (serial,
-                  port->bulk_out_endpointAddress, USB_DIR_OUT, port,
-                  portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
+               /* outdat endpoints */
+               for (j = 0; j < N_OUT_URB; ++j) {
+                       portdata->out_urbs[j] = option_setup_urb (serial,
+                       port->bulk_out_endpointAddress, USB_DIR_OUT, port,
+                       portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
+               }
        }
 }
 
index c96714bb1cb829be62f012527da26d74cb0b9c65..d88704387202389af2376b848497ee2cf06a3210 100644 (file)
@@ -314,7 +314,7 @@ static void pl2303_send(struct usb_serial_port *port)
                // TODO: reschedule pl2303_send
        }
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 static int pl2303_write_room(struct usb_serial_port *port)
@@ -600,7 +600,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
        unsigned int c_cflag;
        int bps;
        long timeout;
-       wait_queue_t wait;                                              \
+       wait_queue_t wait;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
index 9c36f0ece20ff6b43631e860621198f694400d5f..a30135c7cfe6a4f59550e2fce18fd18e43d4fc15 100644 (file)
@@ -162,12 +162,19 @@ static void destroy_serial(struct kref *kref)
                }
        }
 
+       flush_scheduled_work();         /* port->work */
+
        usb_put_dev(serial->dev);
 
        /* free up any memory that we allocated */
        kfree (serial);
 }
 
+void usb_serial_put(struct usb_serial *serial)
+{
+       kref_put(&serial->kref, destroy_serial);
+}
+
 /*****************************************************************************
  * Driver tty interface functions
  *****************************************************************************/
@@ -201,12 +208,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
         
        ++port->open_count;
 
-       if (port->open_count == 1) {
+       /* set up our port structure making the tty driver
+        * remember our port object, and us it */
+       tty->driver_data = port;
+       port->tty = tty;
 
-               /* set up our port structure making the tty driver
-                * remember our port object, and us it */
-               tty->driver_data = port;
-               port->tty = tty;
+       if (port->open_count == 1) {
 
                /* lock this module before we call it
                 * this may fail, which means we must bail out,
@@ -230,9 +237,11 @@ bailout_module_put:
        module_put(serial->type->driver.owner);
 bailout_mutex_unlock:
        port->open_count = 0;
+       tty->driver_data = NULL;
+       port->tty = NULL;
        mutex_unlock(&port->mutex);
 bailout_kref_put:
-       kref_put(&serial->kref, destroy_serial);
+       usb_serial_put(serial);
        return retval;
 }
 
@@ -268,7 +277,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
        }
 
        mutex_unlock(&port->mutex);
-       kref_put(&port->serial->kref, destroy_serial);
+       usb_serial_put(port->serial);
 }
 
 static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
@@ -276,7 +285,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
        struct usb_serial_port *port = tty->driver_data;
        int retval = -EINVAL;
 
-       if (!port)
+       if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
                goto exit;
 
        dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
@@ -296,7 +305,7 @@ exit:
 static int serial_write_room (struct tty_struct *tty) 
 {
        struct usb_serial_port *port = tty->driver_data;
-       int retval = -EINVAL;
+       int retval = -ENODEV;
 
        if (!port)
                goto exit;
@@ -318,7 +327,7 @@ exit:
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 {
        struct usb_serial_port *port = tty->driver_data;
-       int retval = -EINVAL;
+       int retval = -ENODEV;
 
        if (!port)
                goto exit;
@@ -473,7 +482,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
                        begin += length;
                        length = 0;
                }
-               kref_put(&serial->kref, destroy_serial);
+               usb_serial_put(serial);
        }
        *eof = 1;
 done:
@@ -488,19 +497,18 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file)
        struct usb_serial_port *port = tty->driver_data;
 
        if (!port)
-               goto exit;
+               return -ENODEV;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (!port->open_count) {
                dbg("%s - port not open", __FUNCTION__);
-               goto exit;
+               return -ENODEV;
        }
 
        if (port->serial->type->tiocmget)
                return port->serial->type->tiocmget(port, file);
 
-exit:
        return -EINVAL;
 }
 
@@ -510,23 +518,32 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file,
        struct usb_serial_port *port = tty->driver_data;
 
        if (!port)
-               goto exit;
+               return -ENODEV;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (!port->open_count) {
                dbg("%s - port not open", __FUNCTION__);
-               goto exit;
+               return -ENODEV;
        }
 
        if (port->serial->type->tiocmset)
                return port->serial->type->tiocmset(port, file, set, clear);
 
-exit:
        return -EINVAL;
 }
 
-void usb_serial_port_softint(void *private)
+/*
+ * We would be calling tty_wakeup here, but unfortunately some line
+ * disciplines have an annoying habit of calling tty->write from
+ * the write wakeup callback (e.g. n_hdlc.c).
+ */
+void usb_serial_port_softint(struct usb_serial_port *port)
+{
+       schedule_work(&port->work);
+}
+
+static void usb_serial_port_work(void *private)
 {
        struct usb_serial_port *port = private;
        struct tty_struct *tty;
@@ -789,7 +806,7 @@ int usb_serial_probe(struct usb_interface *interface,
                port->serial = serial;
                spin_lock_init(&port->lock);
                mutex_init(&port->mutex);
-               INIT_WORK(&port->work, usb_serial_port_softint, port);
+               INIT_WORK(&port->work, usb_serial_port_work, port);
                serial->port[i] = port;
        }
 
@@ -985,6 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
        struct device *dev = &interface->dev;
        struct usb_serial_port *port;
 
+       usb_serial_console_disconnect(serial);
        dbg ("%s", __FUNCTION__);
 
        usb_set_intfdata (interface, NULL);
@@ -996,7 +1014,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
                }
                /* let the last holder of this object 
                 * cause it to be cleaned up */
-               kref_put(&serial->kref, destroy_serial);
+               usb_serial_put(serial);
        }
        dev_info(dev, "device disconnected\n");
 }
index dc89d87104609524d6b3e07272153a6807459798..d53ea9b11e816c1609a11c8729f67cc1ab622c62 100644 (file)
@@ -236,7 +236,7 @@ struct usb_serial_driver {
 
 extern int  usb_serial_register(struct usb_serial_driver *driver);
 extern void usb_serial_deregister(struct usb_serial_driver *driver);
-extern void usb_serial_port_softint(void *private);
+extern void usb_serial_port_softint(struct usb_serial_port *port);
 
 extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
 extern void usb_serial_disconnect(struct usb_interface *iface);
@@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
 #ifdef CONFIG_USB_SERIAL_CONSOLE
 extern void usb_serial_console_init (int debug, int minor);
 extern void usb_serial_console_exit (void);
+extern void usb_serial_console_disconnect(struct usb_serial *serial);
 #else
 static inline void usb_serial_console_init (int debug, int minor) { }
 static inline void usb_serial_console_exit (void) { }
+static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
 #endif
 
 /* Functions needed by other parts of the usbserial core */
 extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
+extern void usb_serial_put(struct usb_serial *serial);
 extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
 extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
 extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
index f5c3841d4843f7dc1cec0d681ee62dd42dfad322..9e89b8d54f725a19276e075d69a2b814db69d386 100644 (file)
@@ -480,7 +480,7 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
        --priv->outstanding_urbs;
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 
index f806553cd9a4c8929a65b0d3826de27441da5977..5b06fa366098c53e0a41aae5e51b3f0e4ac49f4f 100644 (file)
@@ -388,7 +388,7 @@ static int whiteheat_attach (struct usb_serial *serial)
        if (ret) {
                err("%s: Couldn't send command [%d]", serial->type->description, ret);
                goto no_firmware;
-       } else if (alen != sizeof(command)) {
+       } else if (alen != 2) {
                err("%s: Send command incomplete [%d]", serial->type->description, alen);
                goto no_firmware;
        }
@@ -400,7 +400,7 @@ static int whiteheat_attach (struct usb_serial *serial)
        if (ret) {
                err("%s: Couldn't get results [%d]", serial->type->description, ret);
                goto no_firmware;
-       } else if (alen != sizeof(result)) {
+       } else if (alen != sizeof(*hw_info) + 1) {
                err("%s: Get results incomplete [%d]", serial->type->description, alen);
                goto no_firmware;
        } else if (result[0] != command[0]) {
@@ -1089,9 +1089,7 @@ static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs)
                return;
        }
 
-       usb_serial_port_softint((void *)port);
-
-       schedule_work(&port->work);
+       usb_serial_port_softint(port);
 }
 
 
index 55ee2d36d585824a589113e29cea2f0e94a1bebc..026a587eb8dd2502aedb8916c8e26077c51375fe 100644 (file)
@@ -34,9 +34,8 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/usb.h>
 #include <linux/usb_ch9.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
 #include "usb.h"
 #include "onetouch.h"
 #include "debug.h"
index 5f11e19eaae3ad74458018357ce9bd1f465604fe..5715291ba5400d784ccb59841ef956a881dfb1e0 100644 (file)
@@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *srb)
        int result;
 
        US_DEBUGP("%s called\n", __FUNCTION__);
-
-       mutex_lock(&(us->dev_mutex));
        result = usb_stor_port_reset(us);
-       mutex_unlock(&us->dev_mutex);
-
        return result < 0 ? FAILED : SUCCESS;
 }
 
index f2bc5c9e23d59c7f1a7111b88ffe02df92776e34..8fcec01dc622f29f9fb3f8e6c50030b523b16730 100644 (file)
@@ -131,28 +131,30 @@ static int usbat_write(struct us_data *us,
  * Convenience function to perform a bulk read
  */
 static int usbat_bulk_read(struct us_data *us,
-                                                        unsigned char *data,
-                                                        unsigned int len)
+                          unsigned char *data,
+                          unsigned int len,
+                          int use_sg)
 {
        if (len == 0)
                return USB_STOR_XFER_GOOD;
 
        US_DEBUGP("usbat_bulk_read: len = %d\n", len);
-       return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL);
+       return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL);
 }
 
 /*
  * Convenience function to perform a bulk write
  */
 static int usbat_bulk_write(struct us_data *us,
-                                                       unsigned char *data,
-                                                       unsigned int len)
+                           unsigned char *data,
+                           unsigned int len,
+                           int use_sg)
 {
        if (len == 0)
                return USB_STOR_XFER_GOOD;
 
        US_DEBUGP("usbat_bulk_write:  len = %d\n", len);
-       return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL);
+       return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL);
 }
 
 /*
@@ -317,7 +319,8 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
  */
 static int usbat_read_block(struct us_data *us,
                            unsigned char *content,
-                           unsigned short len)
+                           unsigned short len,
+                           int use_sg)
 {
        int result;
        unsigned char *command = us->iobuf;
@@ -338,7 +341,7 @@ static int usbat_read_block(struct us_data *us,
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
-       result = usbat_bulk_read(us, content, len);
+       result = usbat_bulk_read(us, content, len, use_sg);
        return (result == USB_STOR_XFER_GOOD ?
                        USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
 }
@@ -350,7 +353,8 @@ static int usbat_write_block(struct us_data *us,
                             unsigned char access,
                             unsigned char *content,
                             unsigned short len,
-                            int minutes)
+                            int minutes,
+                            int use_sg)
 {
        int result;
        unsigned char *command = us->iobuf;
@@ -372,7 +376,7 @@ static int usbat_write_block(struct us_data *us,
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
-       result = usbat_bulk_write(us, content, len);
+       result = usbat_bulk_write(us, content, len, use_sg);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
@@ -465,7 +469,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
                                data[1+(j<<1)] = data_out[j];
                        }
 
-                       result = usbat_bulk_write(us, data, num_registers*2);
+                       result = usbat_bulk_write(us, data, num_registers*2, 0);
                        if (result != USB_STOR_XFER_GOOD)
                                return USB_STOR_TRANSPORT_ERROR;
 
@@ -583,7 +587,7 @@ static int usbat_multiple_write(struct us_data *us,
        }
 
        /* Send the data */
-       result = usbat_bulk_write(us, data, num_registers*2);
+       result = usbat_bulk_write(us, data, num_registers*2, 0);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
@@ -606,8 +610,9 @@ static int usbat_multiple_write(struct us_data *us,
  * other related details) are defined beforehand with _set_shuttle_features().
  */
 static int usbat_read_blocks(struct us_data *us,
-                                                        unsigned char *buffer,
-                                                        int len)
+                            unsigned char *buffer,
+                            int len,
+                            int use_sg)
 {
        int result;
        unsigned char *command = us->iobuf;
@@ -627,7 +632,7 @@ static int usbat_read_blocks(struct us_data *us,
                return USB_STOR_TRANSPORT_FAILED;
        
        /* Read the blocks we just asked for */
-       result = usbat_bulk_read(us, buffer, len);
+       result = usbat_bulk_read(us, buffer, len, use_sg);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_FAILED;
 
@@ -648,7 +653,8 @@ static int usbat_read_blocks(struct us_data *us,
  */
 static int usbat_write_blocks(struct us_data *us,
                                                          unsigned char *buffer,
-                                                         int len)
+                             int len,
+                             int use_sg)
 {
        int result;
        unsigned char *command = us->iobuf;
@@ -668,7 +674,7 @@ static int usbat_write_blocks(struct us_data *us,
                return USB_STOR_TRANSPORT_FAILED;
        
        /* Write the data */
-       result = usbat_bulk_write(us, buffer, len);
+       result = usbat_bulk_write(us, buffer, len, use_sg);
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_FAILED;
 
@@ -887,22 +893,28 @@ static int usbat_identify_device(struct us_data *us,
  * Set the transport function based on the device type
  */
 static int usbat_set_transport(struct us_data *us,
-                              struct usbat_info *info)
+                              struct usbat_info *info,
+                              int devicetype)
 {
-       int rc;
 
-       if (!info->devicetype) {
-               rc = usbat_identify_device(us, info);
-               if (rc != USB_STOR_TRANSPORT_GOOD) {
-                       US_DEBUGP("usbat_set_transport: Could not identify device\n");
-                       return 1;
-               }
-       }
+       if (!info->devicetype)
+               info->devicetype = devicetype;
 
-       if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+       if (!info->devicetype)
+               usbat_identify_device(us, info);
+
+       switch (info->devicetype) {
+       default:
+               return USB_STOR_TRANSPORT_ERROR;
+
+       case  USBAT_DEV_HP8200:
                us->transport = usbat_hp8200e_transport;
-       else if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+               break;
+
+       case USBAT_DEV_FLASH:
                us->transport = usbat_flash_transport;
+               break;
+       }
 
        return 0;
 }
@@ -947,7 +959,7 @@ static int usbat_flash_get_sector_count(struct us_data *us,
        msleep(100);
 
        /* Read the device identification data */
-       rc = usbat_read_block(us, reply, 512);
+       rc = usbat_read_block(us, reply, 512, 0);
        if (rc != USB_STOR_TRANSPORT_GOOD)
                goto leave;
 
@@ -1031,7 +1043,7 @@ static int usbat_flash_read_data(struct us_data *us,
                        goto leave;
 
                /* Read the data we just requested */
-               result = usbat_read_blocks(us, buffer, len);
+               result = usbat_read_blocks(us, buffer, len, 0);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        goto leave;
         
@@ -1125,7 +1137,7 @@ static int usbat_flash_write_data(struct us_data *us,
                        goto leave;
 
                /* Write the data */
-               result = usbat_write_blocks(us, buffer, len);
+               result = usbat_write_blocks(us, buffer, len, 0);
                if (result != USB_STOR_TRANSPORT_GOOD)
                        goto leave;
 
@@ -1310,7 +1322,7 @@ static int usbat_select_and_test_registers(struct us_data *us)
 /*
  * Initialize the USBAT processor and the storage device
  */
-int init_usbat(struct us_data *us)
+static int init_usbat(struct us_data *us, int devicetype)
 {
        int rc;
        struct usbat_info *info;
@@ -1392,7 +1404,7 @@ int init_usbat(struct us_data *us)
        US_DEBUGP("INIT 9\n");
 
        /* At this point, we need to detect which device we are using */
-       if (usbat_set_transport(us, info))
+       if (usbat_set_transport(us, info, devicetype))
                return USB_STOR_TRANSPORT_ERROR;
 
        US_DEBUGP("INIT 10\n");
@@ -1503,10 +1515,10 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
         * AT SPEED 4 IS UNRELIABLE!!!
         */
 
-       if ( (result = usbat_write_block(us, 
+       if ((result = usbat_write_block(us,
                        USBAT_ATA, srb->cmnd, 12,
-                       srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) !=
-                               USB_STOR_TRANSPORT_GOOD) {
+                               (srb->cmnd[0]==GPCMD_BLANK ? 75 : 10), 0) !=
+                            USB_STOR_TRANSPORT_GOOD)) {
                return result;
        }
 
@@ -1533,7 +1545,7 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
                        len = *status;
 
 
-               result = usbat_read_block(us, srb->request_buffer, len);
+               result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg);
 
                /* Debug-print the first 32 bytes of the transfer */
 
@@ -1695,6 +1707,22 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
        return USB_STOR_TRANSPORT_FAILED;
 }
 
+int init_usbat_cd(struct us_data *us)
+{
+       return init_usbat(us, USBAT_DEV_HP8200);
+}
+
+
+int init_usbat_flash(struct us_data *us)
+{
+       return init_usbat(us, USBAT_DEV_FLASH);
+}
+
+int init_usbat_probe(struct us_data *us)
+{
+       return init_usbat(us, 0);
+}
+
 /*
  * Default transport function. Attempts to detect which transport function
  * should be called, makes it the new default, and calls it.
@@ -1708,9 +1736,8 @@ int usbat_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
        struct usbat_info *info = (struct usbat_info*) (us->extra);
 
-       if (usbat_set_transport(us, info))
+       if (usbat_set_transport(us, info, 0))
                return USB_STOR_TRANSPORT_ERROR;
 
        return us->transport(srb, us);  
 }
-
index 25e7d8b340b84db1f315d895623b7c322e655480..3ddf143a1dec25c05a805c0fd33f625a51a21326 100644 (file)
 #define USBAT_FEAT_ET2 0x01
 
 extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us);
-extern int init_usbat(struct us_data *us);
+extern int init_usbat_cd(struct us_data *us);
+extern int init_usbat_flash(struct us_data *us);
+extern int init_usbat_probe(struct us_data *us);
 
 struct usbat_info {
        int devicetype;
index 7ca896a342e3ed1c9711475921f854d464b954ff..19b25c5cafd4e2686ec3db4a5846f52a634a89cc 100644 (file)
@@ -115,19 +115,6 @@ static void usb_stor_blocking_completion(struct urb *urb, struct pt_regs *regs)
 
        complete(urb_done_ptr);
 }
-/* This is the timeout handler which will cancel an URB when its timeout
- * expires.
- */
-static void timeout_handler(unsigned long us_)
-{
-       struct us_data *us = (struct us_data *) us_;
-
-       if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
-               US_DEBUGP("Timeout -- cancelling URB\n");
-               usb_unlink_urb(us->current_urb);
-       }
-}
 
 /* This is the common part of the URB message submission code
  *
@@ -138,7 +125,7 @@ static void timeout_handler(unsigned long us_)
 static int usb_stor_msg_common(struct us_data *us, int timeout)
 {
        struct completion urb_done;
-       struct timer_list to_timer;
+       long timeleft;
        int status;
 
        /* don't submit URBs during abort/disconnect processing */
@@ -185,22 +172,17 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
                }
        }
  
-       /* submit the timeout timer, if a timeout was requested */
-       if (timeout > 0) {
-               init_timer(&to_timer);
-               to_timer.expires = jiffies + timeout;
-               to_timer.function = timeout_handler;
-               to_timer.data = (unsigned long) us;
-               add_timer(&to_timer);
-       }
-
        /* wait for the completion of the URB */
-       wait_for_completion(&urb_done);
-       clear_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+       timeleft = wait_for_completion_interruptible_timeout(
+                       &urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);
  
-       /* clean up the timeout timer */
-       if (timeout > 0)
-               del_timer_sync(&to_timer);
+       clear_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+
+       if (timeleft <= 0) {
+               US_DEBUGP("%s -- cancelling URB\n",
+                         timeleft == 0 ? "Timeout" : "Signal");
+               usb_unlink_urb(us->current_urb);
+       }
 
        /* return the URB status */
        return us->current_urb->status;
@@ -721,16 +703,19 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
         * device reset. */
   Handle_Errors:
 
-       /* Let the SCSI layer know we are doing a reset, set the
-        * RESETTING bit, and clear the ABORTING bit so that the reset
-        * may proceed. */
+       /* Set the RESETTING bit, and clear the ABORTING bit so that
+        * the reset may proceed. */
        scsi_lock(us_to_host(us));
-       usb_stor_report_bus_reset(us);
        set_bit(US_FLIDX_RESETTING, &us->flags);
        clear_bit(US_FLIDX_ABORTING, &us->flags);
        scsi_unlock(us_to_host(us));
 
+       /* We must release the device lock because the pre_reset routine
+        * will want to acquire it. */
+       mutex_unlock(&us->dev_mutex);
        result = usb_stor_port_reset(us);
+       mutex_lock(&us->dev_mutex);
+
        if (result < 0) {
                scsi_lock(us_to_host(us));
                usb_stor_report_device_reset(us);
@@ -1214,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data *us)
                                 0, us->ifnum, NULL, 0);
 }
 
-/* Issue a USB port reset to the device.  But don't do anything if
- * there's more than one interface in the device, so that other users
- * are not affected. */
+/* Issue a USB port reset to the device.  The caller must not hold
+ * us->dev_mutex.
+ */
 int usb_stor_port_reset(struct us_data *us)
 {
-       int result, rc;
+       int result, rc_lock;
 
-       if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-               result = -EIO;
-               US_DEBUGP("No reset during disconnect\n");
-       } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
-               result = -EBUSY;
-               US_DEBUGP("Refusing to reset a multi-interface device\n");
-       } else {
-               result = rc =
-                       usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
-               if (result < 0) {
-                       US_DEBUGP("unable to lock device for reset: %d\n",
-                                       result);
+       result = rc_lock =
+               usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+       if (result < 0)
+               US_DEBUGP("unable to lock device for reset: %d\n", result);
+       else {
+               /* Were we disconnected while waiting for the lock? */
+               if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+                       result = -EIO;
+                       US_DEBUGP("No reset during disconnect\n");
                } else {
-                       result = usb_reset_device(us->pusb_dev);
-                       if (rc)
-                               usb_unlock_device(us->pusb_dev);
-                       US_DEBUGP("usb_reset_device returns %d\n", result);
+                       result = usb_reset_composite_device(
+                                       us->pusb_dev, us->pusb_intf);
+                       US_DEBUGP("usb_reset_composite_device returns %d\n",
+                                       result);
                }
+               if (rc_lock)
+                       usb_unlock_device(us->pusb_dev);
        }
        return result;
 }
index aec5ea8682d5379cd461fe6a9376bfbcacd70b49..543244d421c1f2e24bc934538187a500b56ae3a1 100644 (file)
@@ -78,12 +78,12 @@ UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x0200,
 UNUSUAL_DEV(  0x03f0, 0x0207, 0x0001, 0x0001, 
                "HP",
                "CD-Writer+ 8200e",
-               US_SC_8070, US_PR_USBAT, init_usbat, 0),
+               US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
 
 UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001, 
                "HP",
                "CD-Writer+ CD-4e",
-               US_SC_8070, US_PR_USBAT, init_usbat, 0),
+               US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
 #endif
 
 /* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
@@ -133,6 +133,14 @@ UNUSUAL_DEV(  0x0420, 0x0001, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Jiri Slaby <jirislaby@gmail.com> and
+ * Rene C. Castberg <Rene@Castberg.org> */
+UNUSUAL_DEV(  0x0421, 0x0446, 0x0100, 0x0100,
+               "Nokia",
+               "N80",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
 /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
 UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
                "SMSC",
@@ -216,6 +224,14 @@ UNUSUAL_DEV(  0x04a4, 0x0004, 0x0001, 0x0001,
                "DVD-CAM DZ-MV100A Camcorder",
                US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
 
+/* Patch for Nikon coolpix 2000
+ * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>*/
+UNUSUAL_DEV(  0x04b0, 0x0301, 0x0010, 0x0010,
+               "NIKON",
+               "NIKON DSC E2000",
+               US_SC_DEVICE, US_PR_DEVICE,NULL,
+               US_FL_NOT_LOCKABLE ),
+
 /* Reported by Andreas Bockhold <andreas@bockionline.de> */
 UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
                "NIKON",
@@ -223,13 +239,12 @@ UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY),
 
-/* Patch for Nikon coolpix 2000
- * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>*/
-UNUSUAL_DEV(  0x04b0, 0x0301, 0x0010, 0x0010,
+/* Reported by Jamie Kitson <jamie@staberinde.fsnet.co.uk> */
+UNUSUAL_DEV(  0x04b0, 0x040d, 0x0100, 0x0100,
                "NIKON",
-               "NIKON DSC E2000",
-               US_SC_DEVICE, US_PR_DEVICE,NULL,
-               US_FL_NOT_LOCKABLE ),
+               "NIKON DSC D70s",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
 
 /* BENQ DC5330
  * Reported by Manuel Fombuena <mfombuena@ya.com> and
@@ -393,7 +408,7 @@ UNUSUAL_DEV(  0x04fc, 0x80c2, 0x0100, 0x0100,
 UNUSUAL_DEV(  0x04e6, 0x1010, 0x0000, 0x9999,
                "Shuttle/SCM",
                "USBAT-02",
-               US_SC_SCSI, US_PR_USBAT, init_usbat,
+               US_SC_SCSI, US_PR_USBAT, init_usbat_flash,
                US_FL_SINGLE_LUN),
 #endif
 
@@ -797,7 +812,7 @@ UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009,
 UNUSUAL_DEV(  0x0781, 0x0005, 0x0005, 0x0005,
                "Sandisk",
                "ImageMate SDDR-05b",
-               US_SC_SCSI, US_PR_USBAT, init_usbat,
+               US_SC_SCSI, US_PR_USBAT, init_usbat_flash,
                US_FL_SINGLE_LUN ),
 #endif
 
index dd108634348e3f12d299b320dc119430d700d8b8..e232c7c8990910a285d1f1dad8fcc9acf84b4c0b 100644 (file)
@@ -220,6 +220,37 @@ static int storage_resume(struct usb_interface *iface)
 
 #endif /* CONFIG_PM */
 
+/*
+ * The next two routines get called just before and just after
+ * a USB port reset, whether from this driver or a different one.
+ */
+
+static void storage_pre_reset(struct usb_interface *iface)
+{
+       struct us_data *us = usb_get_intfdata(iface);
+
+       US_DEBUGP("%s\n", __FUNCTION__);
+
+       /* Make sure no command runs during the reset */
+       mutex_lock(&us->dev_mutex);
+}
+
+static void storage_post_reset(struct usb_interface *iface)
+{
+       struct us_data *us = usb_get_intfdata(iface);
+
+       US_DEBUGP("%s\n", __FUNCTION__);
+
+       /* Report the reset to the SCSI core */
+       scsi_lock(us_to_host(us));
+       usb_stor_report_bus_reset(us);
+       scsi_unlock(us_to_host(us));
+
+       /* FIXME: Notify the subdrivers that they need to reinitialize
+        * the device */
+       mutex_unlock(&us->dev_mutex);
+}
+
 /*
  * fill_inquiry_response takes an unsigned char array (which must
  * be at least 36 characters) and populates the vendor name,
@@ -593,6 +624,15 @@ static int get_transport(struct us_data *us)
                break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_ALAUDA
+       case US_PR_ALAUDA:
+               us->transport_name  = "Alauda Control/Bulk";
+               us->transport = alauda_transport;
+               us->transport_reset = usb_stor_Bulk_reset;
+               us->max_lun = 1;
+               break;
+#endif
+
        default:
                return -EIO;
        }
@@ -648,15 +688,6 @@ static int get_protocol(struct us_data *us)
                break;
 #endif
 
-#ifdef CONFIG_USB_STORAGE_ALAUDA
-       case US_PR_ALAUDA:
-               us->transport_name  = "Alauda Control/Bulk";
-               us->transport = alauda_transport;
-               us->transport_reset = usb_stor_Bulk_reset;
-               us->max_lun = 1;
-               break;
-#endif
-
        default:
                return -EIO;
        }
@@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_driver = {
        .suspend =      storage_suspend,
        .resume =       storage_resume,
 #endif
+       .pre_reset =    storage_pre_reset,
+       .post_reset =   storage_post_reset,
        .id_table =     storage_usb_ids,
 };
 
index 989e4d49e5bbea32cf2b04c3e85c815ad8e3c436..7f939d066a5a40151e3e35ab4316d6abe06e25b0 100644 (file)
@@ -313,8 +313,8 @@ static const char __init *mdacon_startup(void)
        mda_num_columns = 80;
        mda_num_lines   = 25;
 
-       mda_vram_base = VGA_MAP_MEM(0xb0000);
        mda_vram_len  = 0x01000;
+       mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len);
 
        mda_index_port  = 0x3b4;
        mda_value_port  = 0x3b5;
index d5a04b68c4d49bf8101f6c9c0b31ec8fa065fffa..e64d42e2449e4dd5ac104042000d0fe005ce09ca 100644 (file)
@@ -391,7 +391,7 @@ static const char __init *vgacon_startup(void)
                        static struct resource ega_console_resource =
                            { "ega", 0x3B0, 0x3BF };
                        vga_video_type = VIDEO_TYPE_EGAM;
-                       vga_vram_end = 0xb8000;
+                       vga_vram_size = 0x8000;
                        display_desc = "EGA+";
                        request_resource(&ioport_resource,
                                         &ega_console_resource);
@@ -401,7 +401,7 @@ static const char __init *vgacon_startup(void)
                        static struct resource mda2_console_resource =
                            { "mda", 0x3BF, 0x3BF };
                        vga_video_type = VIDEO_TYPE_MDA;
-                       vga_vram_end = 0xb2000;
+                       vga_vram_size = 0x2000;
                        display_desc = "*MDA";
                        request_resource(&ioport_resource,
                                         &mda1_console_resource);
@@ -418,7 +418,7 @@ static const char __init *vgacon_startup(void)
                if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
                        int i;
 
-                       vga_vram_end = 0xc0000;
+                       vga_vram_size = 0x8000;
 
                        if (!ORIG_VIDEO_ISVGA) {
                                static struct resource ega_console_resource
@@ -443,7 +443,7 @@ static const char __init *vgacon_startup(void)
                                 * and COE=1 isn't necessarily a good idea)
                                 */
                                vga_vram_base = 0xa0000;
-                               vga_vram_end = 0xb0000;
+                               vga_vram_size = 0x10000;
                                outb_p(6, VGA_GFX_I);
                                outb_p(6, VGA_GFX_D);
 #endif
@@ -475,7 +475,7 @@ static const char __init *vgacon_startup(void)
                        static struct resource cga_console_resource =
                            { "cga", 0x3D4, 0x3D5 };
                        vga_video_type = VIDEO_TYPE_CGA;
-                       vga_vram_end = 0xba000;
+                       vga_vram_size = 0x2000;
                        display_desc = "*CGA";
                        request_resource(&ioport_resource,
                                         &cga_console_resource);
@@ -483,9 +483,8 @@ static const char __init *vgacon_startup(void)
                }
        }
 
-       vga_vram_base = VGA_MAP_MEM(vga_vram_base);
-       vga_vram_end = VGA_MAP_MEM(vga_vram_end);
-       vga_vram_size = vga_vram_end - vga_vram_base;
+       vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
+       vga_vram_end = vga_vram_base + vga_vram_size;
 
        /*
         *      Find out if there is a graphics card present.
@@ -1020,14 +1019,14 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
        char *charmap;
        
        if (vga_video_type != VIDEO_TYPE_EGAM) {
-               charmap = (char *) VGA_MAP_MEM(colourmap);
+               charmap = (char *) VGA_MAP_MEM(colourmap, 0);
                beg = 0x0e;
 #ifdef VGA_CAN_DO_64KB
                if (vga_video_type == VIDEO_TYPE_VGAC)
                        beg = 0x06;
 #endif
        } else {
-               charmap = (char *) VGA_MAP_MEM(blackwmap);
+               charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
                beg = 0x0a;
        }
 
index f3f16fd9f2316d32c89a2d9ae63b47864cd28fb0..4fd2a272e03d350ea3a0cec9c4b1d3c15ca63740 100644 (file)
@@ -1351,7 +1351,7 @@ static int __init vga16fb_probe(struct device *device)
        }
 
        /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
-       info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
+       info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
 
        if (!info->screen_base) {
                printk(KERN_ERR "vga16fb: unable to map device\n");
index 537893a16014cbbdd6d72259e795030625e91a77..8a04216e8b4d37856bec43d273f24b45cadc138e 100644 (file)
@@ -759,7 +759,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 
        /* Discard our unneeded old files struct */
        if (files) {
-               steal_locks(files);
                put_files_struct(files);
                files = NULL;
        }
index d73d75591a3966125003fdc8e6edebca1d7cc5e3..599f36fd0f6712669a759c996bd608872f588d13 100644 (file)
@@ -203,7 +203,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                goto _error;
 
        if (files) {
-               steal_locks(files);
                put_files_struct(files);
                files = NULL;
        }
index f5958f413bd1135787e2dc731f92b562c452d390..44aaba202f78f87083605e11030d1b7613f2ccc0 100644 (file)
@@ -414,21 +414,31 @@ EXPORT_SYMBOL(bdput);
 static struct block_device *bd_acquire(struct inode *inode)
 {
        struct block_device *bdev;
+
        spin_lock(&bdev_lock);
        bdev = inode->i_bdev;
-       if (bdev && igrab(bdev->bd_inode)) {
+       if (bdev) {
+               atomic_inc(&bdev->bd_inode->i_count);
                spin_unlock(&bdev_lock);
                return bdev;
        }
        spin_unlock(&bdev_lock);
+
        bdev = bdget(inode->i_rdev);
        if (bdev) {
                spin_lock(&bdev_lock);
-               if (inode->i_bdev)
-                       __bd_forget(inode);
-               inode->i_bdev = bdev;
-               inode->i_mapping = bdev->bd_inode->i_mapping;
-               list_add(&inode->i_devices, &bdev->bd_inodes);
+               if (!inode->i_bdev) {
+                       /*
+                        * We take an additional bd_inode->i_count for inode,
+                        * and it's released in clear_inode() of inode.
+                        * So, we can access it via ->i_mapping always
+                        * without igrab().
+                        */
+                       atomic_inc(&bdev->bd_inode->i_count);
+                       inode->i_bdev = bdev;
+                       inode->i_mapping = bdev->bd_inode->i_mapping;
+                       list_add(&inode->i_devices, &bdev->bd_inodes);
+               }
                spin_unlock(&bdev_lock);
        }
        return bdev;
@@ -438,10 +448,18 @@ static struct block_device *bd_acquire(struct inode *inode)
 
 void bd_forget(struct inode *inode)
 {
+       struct block_device *bdev = NULL;
+
        spin_lock(&bdev_lock);
-       if (inode->i_bdev)
+       if (inode->i_bdev) {
+               if (inode->i_sb != blockdev_superblock)
+                       bdev = inode->i_bdev;
                __bd_forget(inode);
+       }
        spin_unlock(&bdev_lock);
+
+       if (bdev)
+               iput(bdev->bd_inode);
 }
 
 int bd_claim(struct block_device *bdev, void *holder)
index 940d188e5d14a90730fe170b59eaa426012ef546..59dbc92c2079b88054c6f5852b5c7bd04cbd187c 100644 (file)
@@ -359,12 +359,13 @@ restart:
 }
 
 /*
- * Throw away a dentry - free the inode, dput the parent.
- * This requires that the LRU list has already been
- * removed.
+ * Throw away a dentry - free the inode, dput the parent.  This requires that
+ * the LRU list has already been removed.
+ *
  * Called with dcache_lock, drops it and then regains.
+ * Called with dentry->d_lock held, drops it.
  */
-static inline void prune_one_dentry(struct dentry * dentry)
+static void prune_one_dentry(struct dentry * dentry)
 {
        struct dentry * parent;
 
@@ -382,6 +383,8 @@ static inline void prune_one_dentry(struct dentry * dentry)
 /**
  * prune_dcache - shrink the dcache
  * @count: number of entries to try and free
+ * @sb: if given, ignore dentries for other superblocks
+ *         which are being unmounted.
  *
  * Shrink the dcache. This is done when we need
  * more memory, or simply when we need to unmount
@@ -392,16 +395,29 @@ static inline void prune_one_dentry(struct dentry * dentry)
  * all the dentries are in use.
  */
  
-static void prune_dcache(int count)
+static void prune_dcache(int count, struct super_block *sb)
 {
        spin_lock(&dcache_lock);
        for (; count ; count--) {
                struct dentry *dentry;
                struct list_head *tmp;
+               struct rw_semaphore *s_umount;
 
                cond_resched_lock(&dcache_lock);
 
                tmp = dentry_unused.prev;
+               if (unlikely(sb)) {
+                       /* Try to find a dentry for this sb, but don't try
+                        * too hard, if they aren't near the tail they will
+                        * be moved down again soon
+                        */
+                       int skip = count;
+                       while (skip && tmp != &dentry_unused &&
+                           list_entry(tmp, struct dentry, d_lru)->d_sb != sb) {
+                               skip--;
+                               tmp = tmp->prev;
+                       }
+               }
                if (tmp == &dentry_unused)
                        break;
                list_del_init(tmp);
@@ -427,7 +443,45 @@ static void prune_dcache(int count)
                        spin_unlock(&dentry->d_lock);
                        continue;
                }
-               prune_one_dentry(dentry);
+               /*
+                * If the dentry is not DCACHED_REFERENCED, it is time
+                * to remove it from the dcache, provided the super block is
+                * NULL (which means we are trying to reclaim memory)
+                * or this dentry belongs to the same super block that
+                * we want to shrink.
+                */
+               /*
+                * If this dentry is for "my" filesystem, then I can prune it
+                * without taking the s_umount lock (I already hold it).
+                */
+               if (sb && dentry->d_sb == sb) {
+                       prune_one_dentry(dentry);
+                       continue;
+               }
+               /*
+                * ...otherwise we need to be sure this filesystem isn't being
+                * unmounted, otherwise we could race with
+                * generic_shutdown_super(), and end up holding a reference to
+                * an inode while the filesystem is unmounted.
+                * So we try to get s_umount, and make sure s_root isn't NULL.
+                * (Take a local copy of s_umount to avoid a use-after-free of
+                * `dentry').
+                */
+               s_umount = &dentry->d_sb->s_umount;
+               if (down_read_trylock(s_umount)) {
+                       if (dentry->d_sb->s_root != NULL) {
+                               prune_one_dentry(dentry);
+                               up_read(s_umount);
+                               continue;
+                       }
+                       up_read(s_umount);
+               }
+               spin_unlock(&dentry->d_lock);
+               /* Cannot remove the first dentry, and it isn't appropriate
+                * to move it to the head of the list, so give up, and try
+                * later
+                */
+               break;
        }
        spin_unlock(&dcache_lock);
 }
@@ -630,7 +684,7 @@ void shrink_dcache_parent(struct dentry * parent)
        int found;
 
        while ((found = select_parent(parent)) != 0)
-               prune_dcache(found);
+               prune_dcache(found, parent->d_sb);
 }
 
 /**
@@ -643,9 +697,10 @@ void shrink_dcache_parent(struct dentry * parent)
  * done under dcache_lock.
  *
  */
-void shrink_dcache_anon(struct hlist_head *head)
+void shrink_dcache_anon(struct super_block *sb)
 {
        struct hlist_node *lp;
+       struct hlist_head *head = &sb->s_anon;
        int found;
        do {
                found = 0;
@@ -668,7 +723,7 @@ void shrink_dcache_anon(struct hlist_head *head)
                        }
                }
                spin_unlock(&dcache_lock);
-               prune_dcache(found);
+               prune_dcache(found, sb);
        } while(found);
 }
 
@@ -689,7 +744,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
        if (nr) {
                if (!(gfp_mask & __GFP_FS))
                        return -1;
-               prune_dcache(nr);
+               prune_dcache(nr, NULL);
        }
        return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
 }
index d07858c0b7c4e3885c2d6b31521f3e5668b94007..0b88bf646143c983a36309c3d5f425dcff7ec841 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -866,7 +866,6 @@ int flush_old_exec(struct linux_binprm * bprm)
        bprm->mm = NULL;                /* We're using it now */
 
        /* This is the point of no return */
-       steal_locks(files);
        put_files_struct(files);
 
        current->sas_ss_sp = current->sas_ss_size = 0;
index ab61a8b548292c025c86a4ba87db4dcab08015d8..69435c68c1ed7a1d95618e8864787174a23f92a0 100644 (file)
@@ -2206,63 +2206,6 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
 
 EXPORT_SYMBOL(lock_may_write);
 
-static inline void __steal_locks(struct file *file, fl_owner_t from)
-{
-       struct inode *inode = file->f_dentry->d_inode;
-       struct file_lock *fl = inode->i_flock;
-
-       while (fl) {
-               if (fl->fl_file == file && fl->fl_owner == from)
-                       fl->fl_owner = current->files;
-               fl = fl->fl_next;
-       }
-}
-
-/* When getting ready for executing a binary, we make sure that current
- * has a files_struct on its own. Before dropping the old files_struct,
- * we take over ownership of all locks for all file descriptors we own.
- * Note that we may accidentally steal a lock for a file that a sibling
- * has created since the unshare_files() call.
- */
-void steal_locks(fl_owner_t from)
-{
-       struct files_struct *files = current->files;
-       int i, j;
-       struct fdtable *fdt;
-
-       if (from == files)
-               return;
-
-       lock_kernel();
-       j = 0;
-
-       /*
-        * We are not taking a ref to the file structures, so
-        * we need to acquire ->file_lock.
-        */
-       spin_lock(&files->file_lock);
-       fdt = files_fdtable(files);
-       for (;;) {
-               unsigned long set;
-               i = j * __NFDBITS;
-               if (i >= fdt->max_fdset || i >= fdt->max_fds)
-                       break;
-               set = fdt->open_fds->fds_bits[j++];
-               while (set) {
-                       if (set & 1) {
-                               struct file *file = fdt->fd[i];
-                               if (file)
-                                       __steal_locks(file, from);
-                       }
-                       i++;
-                       set >>= 1;
-               }
-       }
-       spin_unlock(&files->file_lock);
-       unlock_kernel();
-}
-EXPORT_SYMBOL(steal_locks);
-
 static int __init filelock_init(void)
 {
        filelock_cache = kmem_cache_create("file_lock_cache",
index c63a83e8da98b7d6737de1969a86f9c5ed066e35..36e1e136bb0c65bbdf21f0b8b19602c14964dfa1 100644 (file)
@@ -1484,14 +1484,15 @@ static inline void ntfs_flush_dcache_pages(struct page **pages,
                unsigned nr_pages)
 {
        BUG_ON(!nr_pages);
+       /*
+        * Warning: Do not do the decrement at the same time as the call to
+        * flush_dcache_page() because it is a NULL macro on i386 and hence the
+        * decrement never happens so the loop never terminates.
+        */
        do {
-               /*
-                * Warning: Do not do the decrement at the same time as the
-                * call because flush_dcache_page() is a NULL macro on i386
-                * and hence the decrement never happens.
-                */
+               --nr_pages;
                flush_dcache_page(pages[nr_pages]);
-       } while (--nr_pages > 0);
+       } while (nr_pages > 0);
 }
 
 /**
index 7ef1f094de911998a88fe76bda393f136d60ec3c..8851b81e7c5afb7a7d911cb606bb0d2c98512055 100644 (file)
@@ -329,6 +329,7 @@ void delete_partition(struct gendisk *disk, int part)
        p->ios[0] = p->ios[1] = 0;
        p->sectors[0] = p->sectors[1] = 0;
        devfs_remove("%s/part%d", disk->devfs_name, part);
+       sysfs_remove_link(&p->kobj, "subsystem");
        if (p->holder_dir)
                kobject_unregister(p->holder_dir);
        kobject_uevent(&p->kobj, KOBJ_REMOVE);
@@ -363,6 +364,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
        kobject_add(&p->kobj);
        if (!disk->part_uevent_suppress)
                kobject_uevent(&p->kobj, KOBJ_ADD);
+       sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem");
        partition_sysfs_add_subdir(p);
        disk->part[part-1] = p;
 }
@@ -398,6 +400,7 @@ static void disk_sysfs_symlinks(struct gendisk *disk)
                        kfree(disk_name);
                }
        }
+       sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, "subsystem");
 }
 
 /* Not exported, helper to add_disk(). */
@@ -548,5 +551,6 @@ void del_gendisk(struct gendisk *disk)
                put_device(disk->driverfs_dev);
                disk->driverfs_dev = NULL;
        }
+       sysfs_remove_link(&disk->kobj, "subsystem");
        kobject_del(&disk->kobj);
 }
index a66f66bb804979a62cf6233473bdeae191884410..9d5c2add72286d531e26f0471b0e0148e5dbd6b6 100644 (file)
@@ -231,7 +231,7 @@ void generic_shutdown_super(struct super_block *sb)
        if (root) {
                sb->s_root = NULL;
                shrink_dcache_parent(root);
-               shrink_dcache_anon(&sb->s_anon);
+               shrink_dcache_anon(sb);
                dput(root);
                fsync_super(sb);
                lock_super(sb);
index bac27d66151dc18562be4c83ed7b75ff43803d72..26b364c9d62c67226de54101ae6f7faa31f33251 100644 (file)
@@ -1,6 +1,5 @@
 config XFS_FS
        tristate "XFS filesystem support"
-       select EXPORTFS if NFSD!=n
        help
          XFS is a high performance journaling filesystem which originated
          on the SGI IRIX platform.  It is completely multi-threaded, can
@@ -18,11 +17,6 @@ config XFS_FS
          system of your root partition is compiled as a module, you'll need
          to use an initial ramdisk (initrd) to boot.
 
-config XFS_EXPORT
-       bool
-       depends on XFS_FS && EXPORTFS
-       default y
-
 config XFS_QUOTA
        bool "XFS Quota support"
        depends on XFS_FS
@@ -65,18 +59,19 @@ config XFS_POSIX_ACL
          If you don't know what Access Control Lists are, say N.
 
 config XFS_RT
-       bool "XFS Realtime support (EXPERIMENTAL)"
-       depends on XFS_FS && EXPERIMENTAL
+       bool "XFS Realtime subvolume support"
+       depends on XFS_FS
        help
          If you say Y here you will be able to mount and use XFS filesystems
-         which contain a realtime subvolume. The realtime subvolume is a
-         separate area of disk space where only file data is stored. The
-         realtime subvolume is designed to provide very deterministic
-         data rates suitable for media streaming applications.
-
-         See the xfs man page in section 5 for a bit more information.
+         which contain a realtime subvolume.  The realtime subvolume is a
+         separate area of disk space where only file data is stored.  It was
+         originally designed to provide deterministic data rates suitable
+         for media streaming applications, but is also useful as a generic
+         mechanism for ensuring data and metadata/log I/Os are completely
+         separated.  Regular file I/Os are isolated to a separate device
+         from all other requests, and this can be done quite transparently
+         to applications via the inherit-realtime directory inode flag.
 
-         This feature is unsupported at this time, is not yet fully
-         functional, and may cause serious problems.
+         See the xfs man page in section 5 for additional information.
 
          If unsure, say N.
index 5d73eaa1971fbb3679f480cda5d0e616e723d27b..9e7f85986d0de3d766a6cc5ee783bb7cd5a9bdb9 100644 (file)
@@ -59,7 +59,6 @@ xfs-$(CONFIG_XFS_POSIX_ACL)   += xfs_acl.o
 xfs-$(CONFIG_PROC_FS)          += $(XFS_LINUX)/xfs_stats.o
 xfs-$(CONFIG_SYSCTL)           += $(XFS_LINUX)/xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)           += $(XFS_LINUX)/xfs_ioctl32.o
-xfs-$(CONFIG_XFS_EXPORT)       += $(XFS_LINUX)/xfs_export.o
 
 
 xfs-y                          += xfs_alloc.o \
@@ -73,14 +72,12 @@ xfs-y                               += xfs_alloc.o \
                                   xfs_btree.o \
                                   xfs_buf_item.o \
                                   xfs_da_btree.o \
-                                  xfs_dir.o \
                                   xfs_dir2.o \
                                   xfs_dir2_block.o \
                                   xfs_dir2_data.o \
                                   xfs_dir2_leaf.o \
                                   xfs_dir2_node.o \
                                   xfs_dir2_sf.o \
-                                  xfs_dir_leaf.o \
                                   xfs_error.o \
                                   xfs_extfree_item.o \
                                   xfs_fsops.o \
@@ -117,6 +114,7 @@ xfs-y                               += $(addprefix $(XFS_LINUX)/, \
                                   kmem.o \
                                   xfs_aops.o \
                                   xfs_buf.o \
+                                  xfs_export.o \
                                   xfs_file.o \
                                   xfs_fs_subr.o \
                                   xfs_globals.o \
index 2cfd33d4d8aa8af49ca03c0afd9ead31c96a71c3..939bd84bc7ee3c0b137ad10a0353883e03f82946 100644 (file)
 #include <linux/sched.h>
 #include <linux/mm.h>
 
-/*
- * Process flags handling
- */
-
-#define PFLAGS_TEST_NOIO()              (current->flags & PF_NOIO)
-#define PFLAGS_TEST_FSTRANS()           (current->flags & PF_FSTRANS)
-
-#define PFLAGS_SET_NOIO() do {         \
-       current->flags |= PF_NOIO;      \
-} while (0)
-
-#define PFLAGS_CLEAR_NOIO() do {       \
-       current->flags &= ~PF_NOIO;     \
-} while (0)
-
-/* these could be nested, so we save state */
-#define PFLAGS_SET_FSTRANS(STATEP) do {        \
-       *(STATEP) = current->flags;     \
-       current->flags |= PF_FSTRANS;   \
-} while (0)
-
-#define PFLAGS_CLEAR_FSTRANS(STATEP) do { \
-       *(STATEP) = current->flags;     \
-       current->flags &= ~PF_FSTRANS;  \
-} while (0)
-
-/* Restore the PF_FSTRANS state to what was saved in STATEP */
-#define PFLAGS_RESTORE_FSTRANS(STATEP) do {                    \
-       current->flags = ((current->flags & ~PF_FSTRANS) |      \
-                         (*(STATEP) & PF_FSTRANS));            \
-} while (0)
-
-#define PFLAGS_DUP(OSTATEP, NSTATEP) do { \
-       *(NSTATEP) = *(OSTATEP);        \
-} while (0)
-
 /*
  * General memory allocation interfaces
  */
@@ -83,7 +47,7 @@ kmem_flags_convert(unsigned int __nocast flags)
                lflags = GFP_ATOMIC | __GFP_NOWARN;
        } else {
                lflags = GFP_KERNEL | __GFP_NOWARN;
-               if (PFLAGS_TEST_FSTRANS() || (flags & KM_NOFS))
+               if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS))
                        lflags &= ~__GFP_FS;
        }
        return lflags;
index 1b262b790d9c2d04880b32219752b7357c4bcd5d..32e1ce0f04c94b0d7b130c2fc94360f667cb1e89 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -28,7 +28,7 @@ typedef struct {
 } mrlock_t;
 
 #define mrinit(mrp, name)      \
-       ( (mrp)->mr_writer = 0, init_rwsem(&(mrp)->mr_lock) )
+       do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0)
 #define mrlock_init(mrp, t,n,s)        mrinit(mrp, n)
 #define mrfree(mrp)            do { } while (0)
 #define mraccess(mrp)          mraccessf(mrp, 0)
index 194a84490bd1f33e2931de317101f565f0333228..b25090094cca73d97a350b141f12114327fc3405 100644 (file)
@@ -34,20 +34,21 @@ typedef struct semaphore sema_t;
 #define initnsema(sp, val, name)       sema_init(sp, val)
 #define psema(sp, b)                   down(sp)
 #define vsema(sp)                      up(sp)
-#define valusema(sp)                   (atomic_read(&(sp)->count))
-#define freesema(sema)
+#define freesema(sema)                 do { } while (0)
+
+static inline int issemalocked(sema_t *sp)
+{
+       return down_trylock(sp) || (up(sp), 0);
+}
 
 /*
  * Map cpsema (try to get the sema) to down_trylock. We need to switch
  * the return values since cpsema returns 1 (acquired) 0 (failed) and
  * down_trylock returns the reverse 0 (acquired) 1 (failed).
  */
-
-#define cpsema(sp)                     (down_trylock(sp) ? 0 : 1)
-
-/*
- * Didn't do cvsema(sp). Not sure how to map this to up/down/...
- * It does a vsema if the values is < 0 other wise nothing.
- */
+static inline int cpsema(sema_t *sp)
+{
+       return down_trylock(sp) ? 0 : 1;
+}
 
 #endif /* __XFS_SUPPORT_SEMA_H__ */
index 4d191ef39b67a62abd3171ec5499f8868727b37f..3e807b828e221464131d088367496f86f54bb033 100644 (file)
@@ -21,7 +21,6 @@
 #include "xfs_inum.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_trans.h"
 #include "xfs_dmapi.h"
@@ -29,7 +28,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -76,7 +74,7 @@ xfs_page_trace(
        int             mask)
 {
        xfs_inode_t     *ip;
-       vnode_t         *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
        loff_t          isize = i_size_read(inode);
        loff_t          offset = page_offset(page);
        int             delalloc = -1, unmapped = -1, unwritten = -1;
@@ -136,9 +134,10 @@ xfs_destroy_ioend(
 
        for (bh = ioend->io_buffer_head; bh; bh = next) {
                next = bh->b_private;
-               bh->b_end_io(bh, ioend->io_uptodate);
+               bh->b_end_io(bh, !ioend->io_error);
        }
-
+       if (unlikely(ioend->io_error))
+               vn_ioerror(ioend->io_vnode, ioend->io_error, __FILE__,__LINE__);
        vn_iowake(ioend->io_vnode);
        mempool_free(ioend, xfs_ioend_pool);
 }
@@ -180,13 +179,12 @@ xfs_end_bio_unwritten(
        void                    *data)
 {
        xfs_ioend_t             *ioend = data;
-       vnode_t                 *vp = ioend->io_vnode;
+       bhv_vnode_t             *vp = ioend->io_vnode;
        xfs_off_t               offset = ioend->io_offset;
        size_t                  size = ioend->io_size;
-       int                     error;
 
-       if (ioend->io_uptodate)
-               VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error);
+       if (likely(!ioend->io_error))
+               bhv_vop_bmap(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL);
        xfs_destroy_ioend(ioend);
 }
 
@@ -211,7 +209,7 @@ xfs_alloc_ioend(
         * all the I/O from calling the completion routine too early.
         */
        atomic_set(&ioend->io_remaining, 1);
-       ioend->io_uptodate = 1; /* cleared if any I/O fails */
+       ioend->io_error = 0;
        ioend->io_list = NULL;
        ioend->io_type = type;
        ioend->io_vnode = vn_from_inode(inode);
@@ -239,10 +237,10 @@ xfs_map_blocks(
        xfs_iomap_t             *mapp,
        int                     flags)
 {
-       vnode_t                 *vp = vn_from_inode(inode);
+       bhv_vnode_t             *vp = vn_from_inode(inode);
        int                     error, nmaps = 1;
 
-       VOP_BMAP(vp, offset, count, flags, mapp, &nmaps, error);
+       error = bhv_vop_bmap(vp, offset, count, flags, mapp, &nmaps);
        if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)))
                VMODIFY(vp);
        return -error;
@@ -271,16 +269,14 @@ xfs_end_bio(
        if (bio->bi_size)
                return 1;
 
-       ASSERT(ioend);
        ASSERT(atomic_read(&bio->bi_cnt) >= 1);
+       ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error;
 
        /* Toss bio and pass work off to an xfsdatad thread */
-       if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-               ioend->io_uptodate = 0;
        bio->bi_private = NULL;
        bio->bi_end_io = NULL;
-
        bio_put(bio);
+
        xfs_finish_ioend(ioend);
        return 0;
 }
@@ -1127,7 +1123,7 @@ xfs_vm_writepage(
         * then mark the page dirty again and leave the page
         * as is.
         */
-       if (PFLAGS_TEST_FSTRANS() && need_trans)
+       if (current_test_flags(PF_FSTRANS) && need_trans)
                goto out_fail;
 
        /*
@@ -1158,6 +1154,18 @@ out_unlock:
        return error;
 }
 
+STATIC int
+xfs_vm_writepages(
+       struct address_space    *mapping,
+       struct writeback_control *wbc)
+{
+       struct bhv_vnode        *vp = vn_from_inode(mapping->host);
+
+       if (VN_TRUNC(vp))
+               VUNTRUNCATE(vp);
+       return generic_writepages(mapping, wbc);
+}
+
 /*
  * Called to move a page into cleanable state - and from there
  * to be released. Possibly the page is already clean. We always
@@ -1204,7 +1212,7 @@ xfs_vm_releasepage(
        /* If we are already inside a transaction or the thread cannot
         * do I/O, we cannot release this page.
         */
-       if (PFLAGS_TEST_FSTRANS())
+       if (current_test_flags(PF_FSTRANS))
                return 0;
 
        /*
@@ -1231,7 +1239,7 @@ __xfs_get_blocks(
        int                     direct,
        bmapi_flags_t           flags)
 {
-       vnode_t                 *vp = vn_from_inode(inode);
+       bhv_vnode_t             *vp = vn_from_inode(inode);
        xfs_iomap_t             iomap;
        xfs_off_t               offset;
        ssize_t                 size;
@@ -1241,8 +1249,8 @@ __xfs_get_blocks(
        offset = (xfs_off_t)iblock << inode->i_blkbits;
        ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
        size = bh_result->b_size;
-       VOP_BMAP(vp, offset, size,
-               create ? flags : BMAPI_READ, &iomap, &niomap, error);
+       error = bhv_vop_bmap(vp, offset, size,
+                            create ? flags : BMAPI_READ, &iomap, &niomap);
        if (error)
                return -error;
        if (niomap == 0)
@@ -1370,13 +1378,13 @@ xfs_vm_direct_IO(
 {
        struct file     *file = iocb->ki_filp;
        struct inode    *inode = file->f_mapping->host;
-       vnode_t         *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
        xfs_iomap_t     iomap;
        int             maps = 1;
        int             error;
        ssize_t         ret;
 
-       VOP_BMAP(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps, error);
+       error = bhv_vop_bmap(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps);
        if (error)
                return -error;
 
@@ -1409,14 +1417,12 @@ xfs_vm_bmap(
        sector_t                block)
 {
        struct inode            *inode = (struct inode *)mapping->host;
-       vnode_t                 *vp = vn_from_inode(inode);
-       int                     error;
+       bhv_vnode_t             *vp = vn_from_inode(inode);
 
        vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
-
-       VOP_RWLOCK(vp, VRWLOCK_READ);
-       VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error);
-       VOP_RWUNLOCK(vp, VRWLOCK_READ);
+       bhv_vop_rwlock(vp, VRWLOCK_READ);
+       bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF);
+       bhv_vop_rwunlock(vp, VRWLOCK_READ);
        return generic_block_bmap(mapping, block, xfs_get_blocks);
 }
 
@@ -1452,6 +1458,7 @@ struct address_space_operations xfs_address_space_operations = {
        .readpage               = xfs_vm_readpage,
        .readpages              = xfs_vm_readpages,
        .writepage              = xfs_vm_writepage,
+       .writepages             = xfs_vm_writepages,
        .sync_page              = block_sync_page,
        .releasepage            = xfs_vm_releasepage,
        .invalidatepage         = xfs_vm_invalidatepage,
index 60716543c68b2b793f8146b4a099b2345f41069c..706d8c781b8a54b474f7a3d5ecb23a42bf8e8352 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Silicon Graphics, Inc.
+ * Copyright (c) 2005-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -30,9 +30,9 @@ typedef void (*xfs_ioend_func_t)(void *);
 typedef struct xfs_ioend {
        struct xfs_ioend        *io_list;       /* next ioend in chain */
        unsigned int            io_type;        /* delalloc / unwritten */
-       unsigned int            io_uptodate;    /* I/O status register */
+       int                     io_error;       /* I/O error code */
        atomic_t                io_remaining;   /* hold count */
-       struct vnode            *io_vnode;      /* file being written to */
+       struct bhv_vnode        *io_vnode;      /* file being written to */
        struct buffer_head      *io_buffer_head;/* buffer linked list head */
        struct buffer_head      *io_buffer_tail;/* buffer linked list tail */
        size_t                  io_size;        /* size of the extent */
@@ -43,4 +43,4 @@ typedef struct xfs_ioend {
 extern struct address_space_operations xfs_address_space_operations;
 extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
 
-#endif /* __XFS_IOPS_H__ */
+#endif /* __XFS_AOPS_H__ */
index b768ea910bbe00e3741ca9cec61b21cb06a3d9e5..5fb75d9151f20899f69c1608728f393843a0371d 100644 (file)
@@ -21,7 +21,6 @@
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_mount.h"
 #include "xfs_export.h"
 
@@ -97,7 +96,7 @@ xfs_fs_encode_fh(
        int                     len;
        int                     is64 = 0;
 #if XFS_BIG_INUMS
-       vfs_t                   *vfs = vfs_from_sb(inode->i_sb);
+       bhv_vfs_t               *vfs = vfs_from_sb(inode->i_sb);
 
        if (!(vfs->vfs_flag & VFS_32BITINODES)) {
                /* filesystem may contain 64bit inode numbers */
@@ -136,13 +135,13 @@ xfs_fs_get_dentry(
        struct super_block      *sb,
        void                    *data)
 {
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        struct inode            *inode;
        struct dentry           *result;
-       vfs_t                   *vfsp = vfs_from_sb(sb);
+       bhv_vfs_t               *vfsp = vfs_from_sb(sb);
        int                     error;
 
-       VFS_VGET(vfsp, &vp, (fid_t *)data, error);
+       error = bhv_vfs_vget(vfsp, &vp, (fid_t *)data);
        if (error || vp == NULL)
                return ERR_PTR(-ESTALE) ;
 
@@ -160,12 +159,12 @@ xfs_fs_get_parent(
        struct dentry           *child)
 {
        int                     error;
-       vnode_t                 *vp, *cvp;
+       bhv_vnode_t             *vp, *cvp;
        struct dentry           *parent;
 
        cvp = NULL;
        vp = vn_from_inode(child->d_inode);
-       VOP_LOOKUP(vp, &dotdot, &cvp, 0, NULL, NULL, error);
+       error = bhv_vop_lookup(vp, &dotdot, &cvp, 0, NULL, NULL);
        if (unlikely(error))
                return ERR_PTR(-error);
 
index c847416f6d1010ac9ffea5ad764661662472632a..70662371bb11fda80e1be225a9bf32b159595491 100644 (file)
@@ -21,7 +21,6 @@
 #include "xfs_inum.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_trans.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_alloc.h"
 #include "xfs_btree.h"
 #include "xfs_attr_sf.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
@@ -58,15 +56,12 @@ __xfs_file_read(
 {
        struct iovec            iov = {buf, count};
        struct file             *file = iocb->ki_filp;
-       vnode_t                 *vp = vn_from_inode(file->f_dentry->d_inode);
-       ssize_t                 rval;
+       bhv_vnode_t             *vp = vn_from_inode(file->f_dentry->d_inode);
 
        BUG_ON(iocb->ki_pos != pos);
-
        if (unlikely(file->f_flags & O_DIRECT))
                ioflags |= IO_ISDIRECT;
-       VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval);
-       return rval;
+       return bhv_vop_read(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
 }
 
 STATIC ssize_t
@@ -100,15 +95,12 @@ __xfs_file_write(
        struct iovec    iov = {(void __user *)buf, count};
        struct file     *file = iocb->ki_filp;
        struct inode    *inode = file->f_mapping->host;
-       vnode_t         *vp = vn_from_inode(inode);
-       ssize_t         rval;
+       bhv_vnode_t     *vp = vn_from_inode(inode);
 
        BUG_ON(iocb->ki_pos != pos);
        if (unlikely(file->f_flags & O_DIRECT))
                ioflags |= IO_ISDIRECT;
-
-       VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval);
-       return rval;
+       return bhv_vop_write(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
 }
 
 STATIC ssize_t
@@ -140,7 +132,7 @@ __xfs_file_readv(
        loff_t                  *ppos)
 {
        struct inode    *inode = file->f_mapping->host;
-       vnode_t         *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
        struct kiocb    kiocb;
        ssize_t         rval;
 
@@ -149,7 +141,8 @@ __xfs_file_readv(
 
        if (unlikely(file->f_flags & O_DIRECT))
                ioflags |= IO_ISDIRECT;
-       VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval);
+       rval = bhv_vop_read(vp, &kiocb, iov, nr_segs,
+                               &kiocb.ki_pos, ioflags, NULL);
 
        *ppos = kiocb.ki_pos;
        return rval;
@@ -184,7 +177,7 @@ __xfs_file_writev(
        loff_t                  *ppos)
 {
        struct inode    *inode = file->f_mapping->host;
-       vnode_t         *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
        struct kiocb    kiocb;
        ssize_t         rval;
 
@@ -193,7 +186,8 @@ __xfs_file_writev(
        if (unlikely(file->f_flags & O_DIRECT))
                ioflags |= IO_ISDIRECT;
 
-       VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval);
+       rval = bhv_vop_write(vp, &kiocb, iov, nr_segs,
+                                &kiocb.ki_pos, ioflags, NULL);
 
        *ppos = kiocb.ki_pos;
        return rval;
@@ -227,11 +221,8 @@ xfs_file_sendfile(
        read_actor_t            actor,
        void                    *target)
 {
-       vnode_t                 *vp = vn_from_inode(filp->f_dentry->d_inode);
-       ssize_t                 rval;
-
-       VOP_SENDFILE(vp, filp, pos, 0, count, actor, target, NULL, rval);
-       return rval;
+       return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode),
+                               filp, pos, 0, count, actor, target, NULL);
 }
 
 STATIC ssize_t
@@ -242,11 +233,8 @@ xfs_file_sendfile_invis(
        read_actor_t            actor,
        void                    *target)
 {
-       vnode_t                 *vp = vn_from_inode(filp->f_dentry->d_inode);
-       ssize_t                 rval;
-
-       VOP_SENDFILE(vp, filp, pos, IO_INVIS, count, actor, target, NULL, rval);
-       return rval;
+       return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode),
+                               filp, pos, IO_INVIS, count, actor, target, NULL);
 }
 
 STATIC ssize_t
@@ -257,11 +245,8 @@ xfs_file_splice_read(
        size_t                  len,
        unsigned int            flags)
 {
-       vnode_t                 *vp = vn_from_inode(infilp->f_dentry->d_inode);
-       ssize_t                 rval;
-
-       VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, 0, NULL, rval);
-       return rval;
+       return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode),
+                                  infilp, ppos, pipe, len, flags, 0, NULL);
 }
 
 STATIC ssize_t
@@ -272,11 +257,9 @@ xfs_file_splice_read_invis(
        size_t                  len,
        unsigned int            flags)
 {
-       vnode_t                 *vp = vn_from_inode(infilp->f_dentry->d_inode);
-       ssize_t                 rval;
-
-       VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, IO_INVIS, NULL, rval);
-       return rval;
+       return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode),
+                                  infilp, ppos, pipe, len, flags, IO_INVIS,
+                                  NULL);
 }
 
 STATIC ssize_t
@@ -287,11 +270,8 @@ xfs_file_splice_write(
        size_t                  len,
        unsigned int            flags)
 {
-       vnode_t                 *vp = vn_from_inode(outfilp->f_dentry->d_inode);
-       ssize_t                 rval;
-
-       VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, 0, NULL, rval);
-       return rval;
+       return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode),
+                                   pipe, outfilp, ppos, len, flags, 0, NULL);
 }
 
 STATIC ssize_t
@@ -302,11 +282,9 @@ xfs_file_splice_write_invis(
        size_t                  len,
        unsigned int            flags)
 {
-       vnode_t                 *vp = vn_from_inode(outfilp->f_dentry->d_inode);
-       ssize_t                 rval;
-
-       VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, IO_INVIS, NULL, rval);
-       return rval;
+       return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode),
+                                   pipe, outfilp, ppos, len, flags, IO_INVIS,
+                                   NULL);
 }
 
 STATIC int
@@ -314,13 +292,17 @@ xfs_file_open(
        struct inode    *inode,
        struct file     *filp)
 {
-       vnode_t         *vp = vn_from_inode(inode);
-       int             error;
-
        if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
                return -EFBIG;
-       VOP_OPEN(vp, NULL, error);
-       return -error;
+       return -bhv_vop_open(vn_from_inode(inode), NULL);
+}
+
+STATIC int
+xfs_file_close(
+       struct file     *filp)
+{
+       return -bhv_vop_close(vn_from_inode(filp->f_dentry->d_inode), 0,
+                               file_count(filp) > 1 ? L_FALSE : L_TRUE, NULL);
 }
 
 STATIC int
@@ -328,12 +310,11 @@ xfs_file_release(
        struct inode    *inode,
        struct file     *filp)
 {
-       vnode_t         *vp = vn_from_inode(inode);
-       int             error = 0;
+       bhv_vnode_t     *vp = vn_from_inode(inode);
 
        if (vp)
-               VOP_RELEASE(vp, error);
-       return -error;
+               return -bhv_vop_release(vp);
+       return 0;
 }
 
 STATIC int
@@ -342,15 +323,14 @@ xfs_file_fsync(
        struct dentry   *dentry,
        int             datasync)
 {
-       struct inode    *inode = dentry->d_inode;
-       vnode_t         *vp = vn_from_inode(inode);
-       int             error;
+       bhv_vnode_t     *vp = vn_from_inode(dentry->d_inode);
        int             flags = FSYNC_WAIT;
 
        if (datasync)
                flags |= FSYNC_DATA;
-       VOP_FSYNC(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1, error);
-       return -error;
+       if (VN_TRUNC(vp))
+               VUNTRUNCATE(vp);
+       return -bhv_vop_fsync(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1);
 }
 
 #ifdef CONFIG_XFS_DMAPI
@@ -361,16 +341,11 @@ xfs_vm_nopage(
        int                     *type)
 {
        struct inode    *inode = area->vm_file->f_dentry->d_inode;
-       vnode_t         *vp = vn_from_inode(inode);
-       xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
-       int             error;
+       bhv_vnode_t     *vp = vn_from_inode(inode);
 
        ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
-
-       error = XFS_SEND_MMAP(mp, area, 0);
-       if (error)
+       if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), area, 0))
                return NULL;
-
        return filemap_nopage(area, address, type);
 }
 #endif /* CONFIG_XFS_DMAPI */
@@ -382,7 +357,7 @@ xfs_file_readdir(
        filldir_t       filldir)
 {
        int             error = 0;
-       vnode_t         *vp = vn_from_inode(filp->f_dentry->d_inode);
+       bhv_vnode_t     *vp = vn_from_inode(filp->f_dentry->d_inode);
        uio_t           uio;
        iovec_t         iov;
        int             eof = 0;
@@ -417,7 +392,7 @@ xfs_file_readdir(
 
                start_offset = uio.uio_offset;
 
-               VOP_READDIR(vp, &uio, NULL, &eof, error);
+               error = bhv_vop_readdir(vp, &uio, NULL, &eof);
                if ((uio.uio_offset == start_offset) || error) {
                        size = 0;
                        break;
@@ -456,38 +431,28 @@ xfs_file_mmap(
        struct file     *filp,
        struct vm_area_struct *vma)
 {
-       struct inode    *ip = filp->f_dentry->d_inode;
-       vnode_t         *vp = vn_from_inode(ip);
-       vattr_t         vattr;
-       int             error;
-
        vma->vm_ops = &xfs_file_vm_ops;
 
 #ifdef CONFIG_XFS_DMAPI
-       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
+       if (vn_from_inode(filp->f_dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
                vma->vm_ops = &xfs_dmapi_file_vm_ops;
-       }
 #endif /* CONFIG_XFS_DMAPI */
 
-       vattr.va_mask = XFS_AT_UPDATIME;
-       VOP_SETATTR(vp, &vattr, XFS_AT_UPDATIME, NULL, error);
-       if (likely(!error))
-               __vn_revalidate(vp, &vattr);    /* update flags */
+       file_accessed(filp);
        return 0;
 }
 
-
 STATIC long
 xfs_file_ioctl(
        struct file     *filp,
        unsigned int    cmd,
-       unsigned long   arg)
+       unsigned long   p)
 {
        int             error;
        struct inode    *inode = filp->f_dentry->d_inode;
-       vnode_t         *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
 
-       VOP_IOCTL(vp, inode, filp, 0, cmd, (void __user *)arg, error);
+       error = bhv_vop_ioctl(vp, inode, filp, 0, cmd, (void __user *)p);
        VMODIFY(vp);
 
        /* NOTE:  some of the ioctl's return positive #'s as a
@@ -503,13 +468,13 @@ STATIC long
 xfs_file_ioctl_invis(
        struct file     *filp,
        unsigned int    cmd,
-       unsigned long   arg)
+       unsigned long   p)
 {
-       struct inode    *inode = filp->f_dentry->d_inode;
-       vnode_t         *vp = vn_from_inode(inode);
        int             error;
+       struct inode    *inode = filp->f_dentry->d_inode;
+       bhv_vnode_t     *vp = vn_from_inode(inode);
 
-       VOP_IOCTL(vp, inode, filp, IO_INVIS, cmd, (void __user *)arg, error);
+       error = bhv_vop_ioctl(vp, inode, filp, IO_INVIS, cmd, (void __user *)p);
        VMODIFY(vp);
 
        /* NOTE:  some of the ioctl's return positive #'s as a
@@ -528,7 +493,7 @@ xfs_vm_mprotect(
        struct vm_area_struct *vma,
        unsigned int    newflags)
 {
-       vnode_t         *vp = vn_from_inode(vma->vm_file->f_dentry->d_inode);
+       bhv_vnode_t     *vp = vn_from_inode(vma->vm_file->f_dentry->d_inode);
        int             error = 0;
 
        if (vp->v_vfsp->vfs_flag & VFS_DMI) {
@@ -554,24 +519,19 @@ STATIC int
 xfs_file_open_exec(
        struct inode    *inode)
 {
-       vnode_t         *vp = vn_from_inode(inode);
-       xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
-       int             error = 0;
-       xfs_inode_t     *ip;
+       bhv_vnode_t     *vp = vn_from_inode(inode);
 
-       if (vp->v_vfsp->vfs_flag & VFS_DMI) {
-               ip = xfs_vtoi(vp);
-               if (!ip) {
-                       error = -EINVAL;
-                       goto open_exec_out;
-               }
-               if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)) {
-                       error = -XFS_SEND_DATA(mp, DM_EVENT_READ, vp,
+       if (unlikely(vp->v_vfsp->vfs_flag & VFS_DMI)) {
+               xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
+               xfs_inode_t     *ip = xfs_vtoi(vp);
+
+               if (!ip)
+                       return -EINVAL;
+               if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ))
+                       return -XFS_SEND_DATA(mp, DM_EVENT_READ, vp,
                                               0, 0, 0, NULL);
-               }
        }
-open_exec_out:
-       return error;
+       return 0;
 }
 #endif /* HAVE_FOP_OPEN_EXEC */
 
@@ -592,6 +552,7 @@ const struct file_operations xfs_file_operations = {
 #endif
        .mmap           = xfs_file_mmap,
        .open           = xfs_file_open,
+       .flush          = xfs_file_close,
        .release        = xfs_file_release,
        .fsync          = xfs_file_fsync,
 #ifdef HAVE_FOP_OPEN_EXEC
@@ -616,6 +577,7 @@ const struct file_operations xfs_invis_file_operations = {
 #endif
        .mmap           = xfs_file_mmap,
        .open           = xfs_file_open,
+       .flush          = xfs_file_close,
        .release        = xfs_file_release,
        .fsync          = xfs_file_fsync,
 };
index 575f2a790f315e9ff84530ea39d4659c1135756e..dc0562828e760958b22242153111e928f317dbd5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2002,2005-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
  * along with this program; if not, write the Free Software Foundation,
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-
 #include "xfs.h"
 
-/*
- * Stub for no-op vnode operations that return error status.
- */
-int
-fs_noerr(void)
-{
-       return 0;
-}
+int  fs_noerr(void) { return 0; }
+int  fs_nosys(void) { return ENOSYS; }
+void fs_noval(void) { return; }
 
-/*
- * Operation unsupported under this file system.
- */
-int
-fs_nosys(void)
-{
-       return ENOSYS;
-}
-
-/*
- * Stub for inactive, strategy, and read/write lock/unlock.  Does nothing.
- */
-/* ARGSUSED */
-void
-fs_noval(void)
-{
-}
-
-/*
- * vnode pcache layer for vnode_tosspages.
- * 'last' parameter unused but left in for IRIX compatibility
- */
 void
 fs_tosspages(
        bhv_desc_t      *bdp,
@@ -56,18 +28,13 @@ fs_tosspages(
        xfs_off_t       last,
        int             fiopt)
 {
-       vnode_t         *vp = BHV_TO_VNODE(bdp);
+       bhv_vnode_t     *vp = BHV_TO_VNODE(bdp);
        struct inode    *ip = vn_to_inode(vp);
 
        if (VN_CACHED(vp))
                truncate_inode_pages(ip->i_mapping, first);
 }
 
-
-/*
- * vnode pcache layer for vnode_flushinval_pages.
- * 'last' parameter unused but left in for IRIX compatibility
- */
 void
 fs_flushinval_pages(
        bhv_desc_t      *bdp,
@@ -75,20 +42,17 @@ fs_flushinval_pages(
        xfs_off_t       last,
        int             fiopt)
 {
-       vnode_t         *vp = BHV_TO_VNODE(bdp);
+       bhv_vnode_t     *vp = BHV_TO_VNODE(bdp);
        struct inode    *ip = vn_to_inode(vp);
 
        if (VN_CACHED(vp)) {
+               if (VN_TRUNC(vp))
+                       VUNTRUNCATE(vp);
                filemap_write_and_wait(ip->i_mapping);
-
                truncate_inode_pages(ip->i_mapping, first);
        }
 }
 
-/*
- * vnode pcache layer for vnode_flush_pages.
- * 'last' parameter unused but left in for IRIX compatibility
- */
 int
 fs_flush_pages(
        bhv_desc_t      *bdp,
@@ -97,15 +61,16 @@ fs_flush_pages(
        uint64_t        flags,
        int             fiopt)
 {
-       vnode_t         *vp = BHV_TO_VNODE(bdp);
+       bhv_vnode_t     *vp = BHV_TO_VNODE(bdp);
        struct inode    *ip = vn_to_inode(vp);
 
-       if (VN_CACHED(vp)) {
+       if (VN_DIRTY(vp)) {
+               if (VN_TRUNC(vp))
+                       VUNTRUNCATE(vp);
                filemap_fdatawrite(ip->i_mapping);
                if (flags & XFS_B_ASYNC)
                        return 0;
                filemap_fdatawait(ip->i_mapping);
        }
-
        return 0;
 }
index 6e8085f346357679a89e3c2292ced09ed61e8fa7..6c162c3dde7efb44ee4f1abbb430591974244b82 100644 (file)
@@ -45,6 +45,7 @@ xfs_param_t xfs_params = {
        .xfs_buf_age    = {     1*100,          15*100,         7200*100},
        .inherit_nosym  = {     0,              0,              1       },
        .rotorstep      = {     1,              1,              255     },
+       .inherit_nodfrg = {     0,              1,              1       },
 };
 
 /*
index 84478491609b8e8566cbab3779cd38c1306f7130..6e52a5dd38d86333cd50ede6dfbe4a9c74e9c2f1 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -31,7 +30,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
@@ -78,7 +76,7 @@ xfs_find_handle(
        xfs_handle_t            handle;
        xfs_fsop_handlereq_t    hreq;
        struct inode            *inode;
-       struct vnode            *vp;
+       bhv_vnode_t             *vp;
 
        if (copy_from_user(&hreq, arg, sizeof(hreq)))
                return -XFS_ERROR(EFAULT);
@@ -192,7 +190,7 @@ xfs_vget_fsop_handlereq(
        xfs_mount_t             *mp,
        struct inode            *parinode,      /* parent inode pointer    */
        xfs_fsop_handlereq_t    *hreq,
-       vnode_t                 **vp,
+       bhv_vnode_t             **vp,
        struct inode            **inode)
 {
        void                    __user *hanp;
@@ -202,7 +200,7 @@ xfs_vget_fsop_handlereq(
        xfs_handle_t            handle;
        xfs_inode_t             *ip;
        struct inode            *inodep;
-       vnode_t                 *vpp;
+       bhv_vnode_t             *vpp;
        xfs_ino_t               ino;
        __u32                   igen;
        int                     error;
@@ -277,7 +275,7 @@ xfs_open_by_handle(
        struct file             *filp;
        struct inode            *inode;
        struct dentry           *dentry;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        xfs_fsop_handlereq_t    hreq;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -362,7 +360,7 @@ xfs_readlink_by_handle(
        struct uio              auio;
        struct inode            *inode;
        xfs_fsop_handlereq_t    hreq;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        __u32                   olen;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -393,9 +391,11 @@ xfs_readlink_by_handle(
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_resid  = olen;
 
-       VOP_READLINK(vp, &auio, IO_INVIS, NULL, error);
-
+       error = bhv_vop_readlink(vp, &auio, IO_INVIS, NULL);
        VN_RELE(vp);
+       if (error)
+               return -error;
+
        return (olen - auio.uio_resid);
 }
 
@@ -411,7 +411,7 @@ xfs_fssetdm_by_handle(
        xfs_fsop_setdm_handlereq_t dmhreq;
        struct inode            *inode;
        bhv_desc_t              *bdp;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
 
        if (!capable(CAP_MKNOD))
                return -XFS_ERROR(EPERM);
@@ -452,7 +452,7 @@ xfs_attrlist_by_handle(
        attrlist_cursor_kern_t  *cursor;
        xfs_fsop_attrlist_handlereq_t al_hreq;
        struct inode            *inode;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        char                    *kbuf;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -472,8 +472,8 @@ xfs_attrlist_by_handle(
                goto out_vn_rele;
 
        cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
-       VOP_ATTR_LIST(vp, kbuf, al_hreq.buflen, al_hreq.flags,
-                       cursor, NULL, error);
+       error = bhv_vop_attr_list(vp, kbuf, al_hreq.buflen, al_hreq.flags,
+                                       cursor, NULL);
        if (error)
                goto out_kfree;
 
@@ -490,7 +490,7 @@ xfs_attrlist_by_handle(
 
 STATIC int
 xfs_attrmulti_attr_get(
-       struct vnode            *vp,
+       bhv_vnode_t             *vp,
        char                    *name,
        char                    __user *ubuf,
        __uint32_t              *len,
@@ -505,7 +505,7 @@ xfs_attrmulti_attr_get(
        if (!kbuf)
                return ENOMEM;
 
-       VOP_ATTR_GET(vp, name, kbuf, len, flags, NULL, error);
+       error = bhv_vop_attr_get(vp, name, kbuf, len, flags, NULL);
        if (error)
                goto out_kfree;
 
@@ -519,7 +519,7 @@ xfs_attrmulti_attr_get(
 
 STATIC int
 xfs_attrmulti_attr_set(
-       struct vnode            *vp,
+       bhv_vnode_t             *vp,
        char                    *name,
        const char              __user *ubuf,
        __uint32_t              len,
@@ -542,7 +542,7 @@ xfs_attrmulti_attr_set(
        if (copy_from_user(kbuf, ubuf, len))
                goto out_kfree;
                        
-       VOP_ATTR_SET(vp, name, kbuf, len, flags, NULL, error);
+       error = bhv_vop_attr_set(vp, name, kbuf, len, flags, NULL);
 
  out_kfree:
        kfree(kbuf);
@@ -551,20 +551,15 @@ xfs_attrmulti_attr_set(
 
 STATIC int
 xfs_attrmulti_attr_remove(
-       struct vnode            *vp,
+       bhv_vnode_t             *vp,
        char                    *name,
        __uint32_t              flags)
 {
-       int                     error;
-
-
        if (IS_RDONLY(&vp->v_inode))
                return -EROFS;
        if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))
                return EPERM;
-
-       VOP_ATTR_REMOVE(vp, name, flags, NULL, error);
-       return error;
+       return bhv_vop_attr_remove(vp, name, flags, NULL);
 }
 
 STATIC int
@@ -578,7 +573,7 @@ xfs_attrmulti_by_handle(
        xfs_attr_multiop_t      *ops;
        xfs_fsop_attrmulti_handlereq_t am_hreq;
        struct inode            *inode;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        unsigned int            i, size;
        char                    *attr_name;
 
@@ -658,7 +653,7 @@ xfs_attrmulti_by_handle(
 STATIC int
 xfs_ioc_space(
        bhv_desc_t              *bdp,
-       vnode_t                 *vp,
+       bhv_vnode_t             *vp,
        struct file             *filp,
        int                     flags,
        unsigned int            cmd,
@@ -682,7 +677,7 @@ xfs_ioc_fsgeometry(
 
 STATIC int
 xfs_ioc_xattr(
-       vnode_t                 *vp,
+       bhv_vnode_t             *vp,
        xfs_inode_t             *ip,
        struct file             *filp,
        unsigned int            cmd,
@@ -711,7 +706,7 @@ xfs_ioctl(
        void                    __user *arg)
 {
        int                     error;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        xfs_inode_t             *ip;
        xfs_mount_t             *mp;
 
@@ -962,7 +957,7 @@ xfs_ioctl(
 STATIC int
 xfs_ioc_space(
        bhv_desc_t              *bdp,
-       vnode_t                 *vp,
+       bhv_vnode_t             *vp,
        struct file             *filp,
        int                     ioflags,
        unsigned int            cmd,
@@ -1153,14 +1148,14 @@ xfs_di2lxflags(
 
 STATIC int
 xfs_ioc_xattr(
-       vnode_t                 *vp,
+       bhv_vnode_t             *vp,
        xfs_inode_t             *ip,
        struct file             *filp,
        unsigned int            cmd,
        void                    __user *arg)
 {
        struct fsxattr          fa;
-       struct vattr            *vattr;
+       struct bhv_vattr        *vattr;
        int                     error = 0;
        int                     attr_flags;
        unsigned int            flags;
@@ -1173,7 +1168,7 @@ xfs_ioc_xattr(
        case XFS_IOC_FSGETXATTR: {
                vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
                                 XFS_AT_NEXTENTS | XFS_AT_PROJID;
-               VOP_GETATTR(vp, vattr, 0, NULL, error);
+               error = bhv_vop_getattr(vp, vattr, 0, NULL);
                if (unlikely(error)) {
                        error = -error;
                        break;
@@ -1206,7 +1201,7 @@ xfs_ioc_xattr(
                vattr->va_extsize = fa.fsx_extsize;
                vattr->va_projid  = fa.fsx_projid;
 
-               VOP_SETATTR(vp, vattr, attr_flags, NULL, error);
+               error = bhv_vop_setattr(vp, vattr, attr_flags, NULL);
                if (likely(!error))
                        __vn_revalidate(vp, vattr);     /* update flags */
                error = -error;
@@ -1216,7 +1211,7 @@ xfs_ioc_xattr(
        case XFS_IOC_FSGETXATTRA: {
                vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \
                                 XFS_AT_ANEXTENTS | XFS_AT_PROJID;
-               VOP_GETATTR(vp, vattr, 0, NULL, error);
+               error = bhv_vop_getattr(vp, vattr, 0, NULL);
                if (unlikely(error)) {
                        error = -error;
                        break;
@@ -1262,7 +1257,7 @@ xfs_ioc_xattr(
                vattr->va_xflags = xfs_merge_ioc_xflags(flags,
                                                        xfs_ip2xflags(ip));
 
-               VOP_SETATTR(vp, vattr, attr_flags, NULL, error);
+               error = bhv_vop_setattr(vp, vattr, attr_flags, NULL);
                if (likely(!error))
                        __vn_revalidate(vp, vattr);     /* update flags */
                error = -error;
index 251bfe451a3f696fc89be210eac27ac7cf04e19b..601f01c92f7f49afb49ce30f506571c5a126f2ca 100644 (file)
@@ -114,7 +114,7 @@ xfs_compat_ioctl(
        unsigned long   arg)
 {
        struct inode    *inode = file->f_dentry->d_inode;
-       vnode_t         *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
        int             error;
 
        switch (cmd) {
@@ -193,7 +193,7 @@ xfs_compat_ioctl(
                return -ENOIOCTLCMD;
        }
 
-       VOP_IOCTL(vp, inode, file, mode, cmd, (void __user *)arg, error);
+       error = bhv_vop_ioctl(vp, inode, file, mode, cmd, (void __user *)arg);
        VMODIFY(vp);
 
        return error;
index 2e2e275c786f2e98f617ef7d720e1b0b617a4643..12810baeb5d4ad7e4c54c7690b08d2fa3fe9de1c 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -61,7 +59,7 @@
  */
 xfs_inode_t *
 xfs_vtoi(
-       struct vnode    *vp)
+       bhv_vnode_t     *vp)
 {
        bhv_desc_t      *bdp;
 
@@ -80,7 +78,7 @@ void
 xfs_synchronize_atime(
        xfs_inode_t     *ip)
 {
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        vp = XFS_ITOV_NULL(ip);
        if (vp) {
@@ -200,14 +198,10 @@ xfs_ichgtime_fast(
 STATIC void
 xfs_validate_fields(
        struct inode    *ip,
-       struct vattr    *vattr)
+       bhv_vattr_t     *vattr)
 {
-       vnode_t         *vp = vn_from_inode(ip);
-       int             error;
-
        vattr->va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS;
-       VOP_GETATTR(vp, vattr, ATTR_LAZY, NULL, error);
-       if (likely(!error)) {
+       if (!bhv_vop_getattr(vn_from_inode(ip), vattr, ATTR_LAZY, NULL)) {
                ip->i_nlink = vattr->va_nlink;
                ip->i_blocks = vattr->va_nblocks;
 
@@ -225,7 +219,7 @@ xfs_validate_fields(
  */
 STATIC int
 xfs_init_security(
-       struct vnode    *vp,
+       bhv_vnode_t     *vp,
        struct inode    *dir)
 {
        struct inode    *ip = vn_to_inode(vp);
@@ -241,7 +235,7 @@ xfs_init_security(
                return -error;
        }
 
-       VOP_ATTR_SET(vp, name, value, length, ATTR_SECURE, NULL, error);
+       error = bhv_vop_attr_set(vp, name, value, length, ATTR_SECURE, NULL);
        if (!error)
                VMODIFY(vp);
 
@@ -264,13 +258,12 @@ xfs_has_fs_struct(struct task_struct *task)
 
 STATIC inline void
 xfs_cleanup_inode(
-       vnode_t         *dvp,
-       vnode_t         *vp,
+       bhv_vnode_t     *dvp,
+       bhv_vnode_t     *vp,
        struct dentry   *dentry,
        int             mode)
 {
        struct dentry   teardown = {};
-       int             error;
 
        /* Oh, the horror.
         * If we can't add the ACL or we fail in
@@ -281,9 +274,9 @@ xfs_cleanup_inode(
        teardown.d_name = dentry->d_name;
 
        if (S_ISDIR(mode))
-               VOP_RMDIR(dvp, &teardown, NULL, error);
+               bhv_vop_rmdir(dvp, &teardown, NULL);
        else
-               VOP_REMOVE(dvp, &teardown, NULL, error);
+               bhv_vop_remove(dvp, &teardown, NULL);
        VN_RELE(vp);
 }
 
@@ -295,8 +288,8 @@ xfs_vn_mknod(
        dev_t           rdev)
 {
        struct inode    *ip;
-       vattr_t         vattr = { 0 };
-       vnode_t         *vp = NULL, *dvp = vn_from_inode(dir);
+       bhv_vattr_t     vattr = { 0 };
+       bhv_vnode_t     *vp = NULL, *dvp = vn_from_inode(dir);
        xfs_acl_t       *default_acl = NULL;
        attrexists_t    test_default_acl = _ACL_DEFAULT_EXISTS;
        int             error;
@@ -330,10 +323,10 @@ xfs_vn_mknod(
                vattr.va_mask |= XFS_AT_RDEV;
                /*FALLTHROUGH*/
        case S_IFREG:
-               VOP_CREATE(dvp, dentry, &vattr, &vp, NULL, error);
+               error = bhv_vop_create(dvp, dentry, &vattr, &vp, NULL);
                break;
        case S_IFDIR:
-               VOP_MKDIR(dvp, dentry, &vattr, &vp, NULL, error);
+               error = bhv_vop_mkdir(dvp, dentry, &vattr, &vp, NULL);
                break;
        default:
                error = EINVAL;
@@ -396,14 +389,14 @@ xfs_vn_lookup(
        struct dentry   *dentry,
        struct nameidata *nd)
 {
-       struct vnode    *vp = vn_from_inode(dir), *cvp;
+       bhv_vnode_t     *vp = vn_from_inode(dir), *cvp;
        int             error;
 
        if (dentry->d_name.len >= MAXNAMELEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       VOP_LOOKUP(vp, dentry, &cvp, 0, NULL, NULL, error);
-       if (error) {
+       error = bhv_vop_lookup(vp, dentry, &cvp, 0, NULL, NULL);
+       if (unlikely(error)) {
                if (unlikely(error != ENOENT))
                        return ERR_PTR(-error);
                d_add(dentry, NULL);
@@ -420,9 +413,9 @@ xfs_vn_link(
        struct dentry   *dentry)
 {
        struct inode    *ip;    /* inode of guy being linked to */
-       vnode_t         *tdvp;  /* target directory for new name/link */
-       vnode_t         *vp;    /* vp of name being linked */
-       vattr_t         vattr;
+       bhv_vnode_t     *tdvp;  /* target directory for new name/link */
+       bhv_vnode_t     *vp;    /* vp of name being linked */
+       bhv_vattr_t     vattr;
        int             error;
 
        ip = old_dentry->d_inode;       /* inode being linked to */
@@ -432,7 +425,7 @@ xfs_vn_link(
        tdvp = vn_from_inode(dir);
        vp = vn_from_inode(ip);
 
-       VOP_LINK(tdvp, vp, dentry, NULL, error);
+       error = bhv_vop_link(tdvp, vp, dentry, NULL);
        if (likely(!error)) {
                VMODIFY(tdvp);
                VN_HOLD(vp);
@@ -448,14 +441,14 @@ xfs_vn_unlink(
        struct dentry   *dentry)
 {
        struct inode    *inode;
-       vnode_t         *dvp;   /* directory containing name to remove */
-       vattr_t         vattr;
+       bhv_vnode_t     *dvp;   /* directory containing name to remove */
+       bhv_vattr_t     vattr;
        int             error;
 
        inode = dentry->d_inode;
        dvp = vn_from_inode(dir);
 
-       VOP_REMOVE(dvp, dentry, NULL, error);
+       error = bhv_vop_remove(dvp, dentry, NULL);
        if (likely(!error)) {
                xfs_validate_fields(dir, &vattr);       /* size needs update */
                xfs_validate_fields(inode, &vattr);
@@ -470,27 +463,26 @@ xfs_vn_symlink(
        const char      *symname)
 {
        struct inode    *ip;
-       vattr_t         vattr = { 0 };
-       vnode_t         *dvp;   /* directory containing name of symlink */
-       vnode_t         *cvp;   /* used to lookup symlink to put in dentry */
+       bhv_vattr_t     va = { 0 };
+       bhv_vnode_t     *dvp;   /* directory containing name of symlink */
+       bhv_vnode_t     *cvp;   /* used to lookup symlink to put in dentry */
        int             error;
 
        dvp = vn_from_inode(dir);
        cvp = NULL;
 
-       vattr.va_mode = S_IFLNK |
+       va.va_mode = S_IFLNK |
                (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
-       vattr.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
+       va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
 
-       error = 0;
-       VOP_SYMLINK(dvp, dentry, &vattr, (char *)symname, &cvp, NULL, error);
+       error = bhv_vop_symlink(dvp, dentry, &va, (char *)symname, &cvp, NULL);
        if (likely(!error && cvp)) {
                error = xfs_init_security(cvp, dir);
                if (likely(!error)) {
                        ip = vn_to_inode(cvp);
                        d_instantiate(dentry, ip);
-                       xfs_validate_fields(dir, &vattr);
-                       xfs_validate_fields(ip, &vattr);
+                       xfs_validate_fields(dir, &va);
+                       xfs_validate_fields(ip, &va);
                } else {
                        xfs_cleanup_inode(dvp, cvp, dentry, 0);
                }
@@ -504,11 +496,11 @@ xfs_vn_rmdir(
        struct dentry   *dentry)
 {
        struct inode    *inode = dentry->d_inode;
-       vnode_t         *dvp = vn_from_inode(dir);
-       vattr_t         vattr;
+       bhv_vnode_t     *dvp = vn_from_inode(dir);
+       bhv_vattr_t     vattr;
        int             error;
 
-       VOP_RMDIR(dvp, dentry, NULL, error);
+       error = bhv_vop_rmdir(dvp, dentry, NULL);
        if (likely(!error)) {
                xfs_validate_fields(inode, &vattr);
                xfs_validate_fields(dir, &vattr);
@@ -524,15 +516,15 @@ xfs_vn_rename(
        struct dentry   *ndentry)
 {
        struct inode    *new_inode = ndentry->d_inode;
-       vnode_t         *fvp;   /* from directory */
-       vnode_t         *tvp;   /* target directory */
-       vattr_t         vattr;
+       bhv_vnode_t     *fvp;   /* from directory */
+       bhv_vnode_t     *tvp;   /* target directory */
+       bhv_vattr_t     vattr;
        int             error;
 
        fvp = vn_from_inode(odir);
        tvp = vn_from_inode(ndir);
 
-       VOP_RENAME(fvp, odentry, tvp, ndentry, NULL, error);
+       error = bhv_vop_rename(fvp, odentry, tvp, ndentry, NULL);
        if (likely(!error)) {
                if (new_inode)
                        xfs_validate_fields(new_inode, &vattr);
@@ -553,7 +545,7 @@ xfs_vn_follow_link(
        struct dentry           *dentry,
        struct nameidata        *nd)
 {
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        uio_t                   *uio;
        iovec_t                 iov;
        int                     error;
@@ -586,8 +578,8 @@ xfs_vn_follow_link(
        uio->uio_resid = MAXPATHLEN;
        uio->uio_iovcnt = 1;
 
-       VOP_READLINK(vp, uio, 0, NULL, error);
-       if (error) {
+       error = bhv_vop_readlink(vp, uio, 0, NULL);
+       if (unlikely(error)) {
                kfree(link);
                link = ERR_PTR(-error);
        } else {
@@ -618,12 +610,7 @@ xfs_vn_permission(
        int             mode,
        struct nameidata *nd)
 {
-       vnode_t         *vp = vn_from_inode(inode);
-       int             error;
-
-       mode <<= 6;             /* convert from linux to vnode access bits */
-       VOP_ACCESS(vp, mode, NULL, error);
-       return -error;
+       return -bhv_vop_access(vn_from_inode(inode), mode << 6, NULL);
 }
 #else
 #define xfs_vn_permission NULL
@@ -636,14 +623,14 @@ xfs_vn_getattr(
        struct kstat    *stat)
 {
        struct inode    *inode = dentry->d_inode;
-       vnode_t         *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
        int             error = 0;
 
        if (unlikely(vp->v_flag & VMODIFIED))
                error = vn_revalidate(vp);
        if (!error)
                generic_fillattr(inode, stat);
-       return 0;
+       return -error;
 }
 
 STATIC int
@@ -653,8 +640,8 @@ xfs_vn_setattr(
 {
        struct inode    *inode = dentry->d_inode;
        unsigned int    ia_valid = attr->ia_valid;
-       vnode_t         *vp = vn_from_inode(inode);
-       vattr_t         vattr = { 0 };
+       bhv_vnode_t     *vp = vn_from_inode(inode);
+       bhv_vattr_t     vattr = { 0 };
        int             flags = 0;
        int             error;
 
@@ -697,7 +684,7 @@ xfs_vn_setattr(
                flags |= ATTR_NONBLOCK;
 #endif
 
-       VOP_SETATTR(vp, &vattr, flags, NULL, error);
+       error = bhv_vop_setattr(vp, &vattr, flags, NULL);
        if (likely(!error))
                __vn_revalidate(vp, &vattr);
        return -error;
@@ -718,7 +705,7 @@ xfs_vn_setxattr(
        size_t          size,
        int             flags)
 {
-       vnode_t         *vp = vn_from_inode(dentry->d_inode);
+       bhv_vnode_t     *vp = vn_from_inode(dentry->d_inode);
        char            *attr = (char *)name;
        attrnames_t     *namesp;
        int             xflags = 0;
@@ -748,7 +735,7 @@ xfs_vn_getxattr(
        void            *data,
        size_t          size)
 {
-       vnode_t         *vp = vn_from_inode(dentry->d_inode);
+       bhv_vnode_t     *vp = vn_from_inode(dentry->d_inode);
        char            *attr = (char *)name;
        attrnames_t     *namesp;
        int             xflags = 0;
@@ -777,7 +764,7 @@ xfs_vn_listxattr(
        char                    *data,
        size_t                  size)
 {
-       vnode_t                 *vp = vn_from_inode(dentry->d_inode);
+       bhv_vnode_t             *vp = vn_from_inode(dentry->d_inode);
        int                     error, xflags = ATTR_KERNAMELS;
        ssize_t                 result;
 
@@ -796,7 +783,7 @@ xfs_vn_removexattr(
        struct dentry   *dentry,
        const char      *name)
 {
-       vnode_t         *vp = vn_from_inode(dentry->d_inode);
+       bhv_vnode_t     *vp = vn_from_inode(dentry->d_inode);
        char            *attr = (char *)name;
        attrnames_t     *namesp;
        int             xflags = 0;
index e9fe43d74768a965f95a72c82741198bd9a65a15..aa26ab906c88cda071d9a2ca54cc79ee2cea6317 100644 (file)
@@ -134,14 +134,21 @@ BUFFER_FNS(PrivateStart, unwritten);
 #define xfs_buf_age_centisecs  xfs_params.xfs_buf_age.val
 #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
 #define xfs_rotorstep          xfs_params.rotorstep.val
+#define xfs_inherit_nodefrag   xfs_params.inherit_nodfrg.val
 
-#ifndef raw_smp_processor_id
-#define raw_smp_processor_id() smp_processor_id()
-#endif
-#define current_cpu()          raw_smp_processor_id()
+#define current_cpu()          (raw_smp_processor_id())
 #define current_pid()          (current->pid)
 #define current_fsuid(cred)    (current->fsuid)
 #define current_fsgid(cred)    (current->fsgid)
+#define current_set_flags(f)   (current->flags |= (f))
+#define current_test_flags(f)  (current->flags & (f))
+#define current_clear_flags(f) (current->flags & ~(f))
+#define current_set_flags_nested(sp, f)                \
+               (*(sp) = current->flags, current->flags |= (f))
+#define current_clear_flags_nested(sp, f)      \
+               (*(sp) = current->flags, current->flags &= ~(f))
+#define current_restore_flags_nested(sp, f)    \
+               (current->flags = ((current->flags & ~(f)) | (*(sp) & (f))))
 
 #define NBPP           PAGE_SIZE
 #define DPPSHFT                (PAGE_SHIFT - 9)
@@ -187,25 +194,9 @@ BUFFER_FNS(PrivateStart, unwritten);
 /* bytes to clicks */
 #define btoc(x)         (((__psunsigned_t)(x)+(NBPC-1))>>BPCSHIFT)
 
-#ifndef ENOATTR
 #define ENOATTR                ENODATA         /* Attribute not found */
-#endif
-
-/* Note: EWRONGFS never visible outside the kernel */
-#define        EWRONGFS        EINVAL          /* Mount with wrong filesystem type */
-
-/*
- * XXX EFSCORRUPTED needs a real value in errno.h. asm-i386/errno.h won't
- *     return codes out of its known range in errno.
- * XXX Also note: needs to be < 1000 and fairly unique on Linux (mustn't
- *     conflict with any code we use already or any code a driver may use)
- * XXX Some options (currently we do #2):
- *     1/ New error code ["Filesystem is corrupted", _after_ glibc updated]
- *     2/ 990 ["Unknown error 990"]
- *     3/ EUCLEAN ["Structure needs cleaning"]
- *     4/ Convert EFSCORRUPTED to EIO [just prior to return into userspace]
- */
-#define EFSCORRUPTED    990            /* Filesystem is corrupted */
+#define EWRONGFS       EINVAL          /* Mount with wrong filesystem type */
+#define EFSCORRUPTED   EUCLEAN         /* Filesystem is corrupted */
 
 #define SYNCHRONIZE()  barrier()
 #define __return_address __builtin_return_address(0)
index 67efe3308980a0110030b58cbfca276a230ee32e..5d9cfd91ad08638012b8365d7d46b4c27959e936 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -206,7 +204,7 @@ xfs_read(
        xfs_fsize_t             n;
        xfs_inode_t             *ip;
        xfs_mount_t             *mp;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        unsigned long           seg;
 
        ip = XFS_BHVTOI(bdp);
@@ -258,7 +256,7 @@ xfs_read(
 
        if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
            !(ioflags & IO_INVIS)) {
-               vrwlock_t locktype = VRWLOCK_READ;
+               bhv_vrwlock_t locktype = VRWLOCK_READ;
                int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags);
 
                ret = -XFS_SEND_DATA(mp, DM_EVENT_READ,
@@ -271,7 +269,7 @@ xfs_read(
        }
 
        if (unlikely((ioflags & IO_ISDIRECT) && VN_CACHED(vp)))
-               VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(*offset)),
+               bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
                                                -1, FI_REMAPF_LOCKED);
 
        xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore,
@@ -313,7 +311,7 @@ xfs_sendfile(
 
        if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
            (!(ioflags & IO_INVIS))) {
-               vrwlock_t locktype = VRWLOCK_READ;
+               bhv_vrwlock_t locktype = VRWLOCK_READ;
                int error;
 
                error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp),
@@ -357,7 +355,7 @@ xfs_splice_read(
 
        if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
            (!(ioflags & IO_INVIS))) {
-               vrwlock_t locktype = VRWLOCK_READ;
+               bhv_vrwlock_t locktype = VRWLOCK_READ;
                int error;
 
                error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp),
@@ -401,7 +399,7 @@ xfs_splice_write(
 
        if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_WRITE) &&
            (!(ioflags & IO_INVIS))) {
-               vrwlock_t locktype = VRWLOCK_WRITE;
+               bhv_vrwlock_t locktype = VRWLOCK_WRITE;
                int error;
 
                error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp),
@@ -458,7 +456,7 @@ xfs_zero_last_block(
        last_fsb = XFS_B_TO_FSBT(mp, isize);
        nimaps = 1;
        error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap,
-                         &nimaps, NULL);
+                         &nimaps, NULL, NULL);
        if (error) {
                return error;
        }
@@ -499,7 +497,7 @@ xfs_zero_last_block(
 
 int                                    /* error (positive) */
 xfs_zero_eof(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        xfs_iocore_t    *io,
        xfs_off_t       offset,         /* starting I/O offset */
        xfs_fsize_t     isize,          /* current inode size */
@@ -510,7 +508,6 @@ xfs_zero_eof(
        xfs_fileoff_t   end_zero_fsb;
        xfs_fileoff_t   zero_count_fsb;
        xfs_fileoff_t   last_fsb;
-       xfs_extlen_t    buf_len_fsb;
        xfs_mount_t     *mp = io->io_mount;
        int             nimaps;
        int             error = 0;
@@ -556,7 +553,7 @@ xfs_zero_eof(
                nimaps = 1;
                zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;
                error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb,
-                                 0, NULL, 0, &imap, &nimaps, NULL);
+                                 0, NULL, 0, &imap, &nimaps, NULL, NULL);
                if (error) {
                        ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
                        ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
@@ -579,16 +576,7 @@ xfs_zero_eof(
                }
 
                /*
-                * There are blocks in the range requested.
-                * Zero them a single write at a time.  We actually
-                * don't zero the entire range returned if it is
-                * too big and simply loop around to get the rest.
-                * That is not the most efficient thing to do, but it
-                * is simple and this path should not be exercised often.
-                */
-               buf_len_fsb = XFS_FILBLKS_MIN(imap.br_blockcount,
-                                             mp->m_writeio_blocks << 8);
-               /*
+                * There are blocks we need to zero.
                 * Drop the inode lock while we're doing the I/O.
                 * We'll still have the iolock to protect us.
                 */
@@ -596,14 +584,13 @@ xfs_zero_eof(
 
                error = xfs_iozero(ip,
                                   XFS_FSB_TO_B(mp, start_zero_fsb),
-                                  XFS_FSB_TO_B(mp, buf_len_fsb),
+                                  XFS_FSB_TO_B(mp, imap.br_blockcount),
                                   end_size);
-
                if (error) {
                        goto out_lock;
                }
 
-               start_zero_fsb = imap.br_startoff + buf_len_fsb;
+               start_zero_fsb = imap.br_startoff + imap.br_blockcount;
                ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
 
                XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
@@ -637,11 +624,11 @@ xfs_write(
        ssize_t                 ret = 0, error = 0;
        xfs_fsize_t             isize, new_size;
        xfs_iocore_t            *io;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        unsigned long           seg;
        int                     iolock;
        int                     eventsent = 0;
-       vrwlock_t               locktype;
+       bhv_vrwlock_t           locktype;
        size_t                  ocount = 0, count;
        loff_t                  pos;
        int                     need_i_mutex = 1, need_flush = 0;
@@ -679,11 +666,11 @@ xfs_write(
        io = &xip->i_iocore;
        mp = io->io_mount;
 
+       vfs_wait_for_freeze(vp->v_vfsp, SB_FREEZE_WRITE);
+
        if (XFS_FORCED_SHUTDOWN(mp))
                return -EIO;
 
-       fs_check_frozen(vp->v_vfsp, SB_FREEZE_WRITE);
-
        if (ioflags & IO_ISDIRECT) {
                xfs_buftarg_t   *target =
                        (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
@@ -814,7 +801,7 @@ retry:
                if (need_flush) {
                        xfs_inval_cached_trace(io, pos, -1,
                                        ctooff(offtoct(pos)), -1);
-                       VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(pos)),
+                       bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)),
                                        -1, FI_REMAPF_LOCKED);
                }
 
@@ -903,79 +890,9 @@ retry:
 
        /* Handle various SYNC-type writes */
        if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
-               /*
-                * If we're treating this as O_DSYNC and we have not updated the
-                * size, force the log.
-                */
-               if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) &&
-                   !(xip->i_update_size)) {
-                       xfs_inode_log_item_t    *iip = xip->i_itemp;
-
-                       /*
-                        * If an allocation transaction occurred
-                        * without extending the size, then we have to force
-                        * the log up the proper point to ensure that the
-                        * allocation is permanent.  We can't count on
-                        * the fact that buffered writes lock out direct I/O
-                        * writes - the direct I/O write could have extended
-                        * the size nontransactionally, then finished before
-                        * we started.  xfs_write_file will think that the file
-                        * didn't grow but the update isn't safe unless the
-                        * size change is logged.
-                        *
-                        * Force the log if we've committed a transaction
-                        * against the inode or if someone else has and
-                        * the commit record hasn't gone to disk (e.g.
-                        * the inode is pinned).  This guarantees that
-                        * all changes affecting the inode are permanent
-                        * when we return.
-                        */
-                       if (iip && iip->ili_last_lsn) {
-                               xfs_log_force(mp, iip->ili_last_lsn,
-                                               XFS_LOG_FORCE | XFS_LOG_SYNC);
-                       } else if (xfs_ipincount(xip) > 0) {
-                               xfs_log_force(mp, (xfs_lsn_t)0,
-                                               XFS_LOG_FORCE | XFS_LOG_SYNC);
-                       }
-
-               } else {
-                       xfs_trans_t     *tp;
-
-                       /*
-                        * O_SYNC or O_DSYNC _with_ a size update are handled
-                        * the same way.
-                        *
-                        * If the write was synchronous then we need to make
-                        * sure that the inode modification time is permanent.
-                        * We'll have updated the timestamp above, so here
-                        * we use a synchronous transaction to log the inode.
-                        * It's not fast, but it's necessary.
-                        *
-                        * If this a dsync write and the size got changed
-                        * non-transactionally, then we need to ensure that
-                        * the size change gets logged in a synchronous
-                        * transaction.
-                        */
-
-                       tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC);
-                       if ((error = xfs_trans_reserve(tp, 0,
-                                                     XFS_SWRITE_LOG_RES(mp),
-                                                     0, 0, 0))) {
-                               /* Transaction reserve failed */
-                               xfs_trans_cancel(tp, 0);
-                       } else {
-                               /* Transaction reserve successful */
-                               xfs_ilock(xip, XFS_ILOCK_EXCL);
-                               xfs_trans_ijoin(tp, xip, XFS_ILOCK_EXCL);
-                               xfs_trans_ihold(tp, xip);
-                               xfs_trans_log_inode(tp, xip, XFS_ILOG_CORE);
-                               xfs_trans_set_sync(tp);
-                               error = xfs_trans_commit(tp, 0, NULL);
-                               xfs_iunlock(xip, XFS_ILOCK_EXCL);
-                       }
-                       if (error)
-                               goto out_unlock_internal;
-               }
+               error = xfs_write_sync_logforce(mp, xip);
+               if (error)
+                       goto out_unlock_internal;
 
                xfs_rwunlock(bdp, locktype);
                if (need_i_mutex)
index 8f4539952350e235991e857cdf97548e230f7632..c77e62efb7420d1bebd3445e55409d426d72fb20 100644 (file)
@@ -18,8 +18,8 @@
 #ifndef __XFS_LRW_H__
 #define __XFS_LRW_H__
 
-struct vnode;
 struct bhv_desc;
+struct bhv_vnode;
 struct xfs_mount;
 struct xfs_iocore;
 struct xfs_inode;
@@ -49,7 +49,7 @@ struct xfs_iomap;
 #define        XFS_CTRUNC4             14
 #define        XFS_CTRUNC5             15
 #define        XFS_CTRUNC6             16
-#define        XFS_BUNMAPI             17
+#define        XFS_BUNMAP              17
 #define        XFS_INVAL_CACHED        18
 #define        XFS_DIORD_ENTER         19
 #define        XFS_DIOWR_ENTER         20
@@ -82,7 +82,7 @@ extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
 extern int xfs_bdstrat_cb(struct xfs_buf *);
 extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
 
-extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t,
+extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t,
                                xfs_fsize_t, xfs_fsize_t);
 extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *,
                                const struct iovec *, unsigned int,
index 68f4793e8a11f27588a3d211ec00a07303f3bca3..f2a0778536f4bb9e7d609c5c0f6a2b3b724f1ac6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -151,7 +149,7 @@ xfs_set_inodeops(
 STATIC __inline__ void
 xfs_revalidate_inode(
        xfs_mount_t             *mp,
-       vnode_t                 *vp,
+       bhv_vnode_t             *vp,
        xfs_inode_t             *ip)
 {
        struct inode            *inode = vn_to_inode(vp);
@@ -206,7 +204,7 @@ xfs_revalidate_inode(
 void
 xfs_initialize_vnode(
        bhv_desc_t              *bdp,
-       vnode_t                 *vp,
+       bhv_vnode_t             *vp,
        bhv_desc_t              *inode_bhv,
        int                     unlock)
 {
@@ -336,7 +334,7 @@ STATIC struct inode *
 xfs_fs_alloc_inode(
        struct super_block      *sb)
 {
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
 
        vp = kmem_zone_alloc(xfs_vnode_zone, KM_SLEEP);
        if (unlikely(!vp))
@@ -359,13 +357,13 @@ xfs_fs_inode_init_once(
 {
        if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
                      SLAB_CTOR_CONSTRUCTOR)
-               inode_init_once(vn_to_inode((vnode_t *)vnode));
+               inode_init_once(vn_to_inode((bhv_vnode_t *)vnode));
 }
 
 STATIC int
 xfs_init_zones(void)
 {
-       xfs_vnode_zone = kmem_zone_init_flags(sizeof(vnode_t), "xfs_vnode_t",
+       xfs_vnode_zone = kmem_zone_init_flags(sizeof(bhv_vnode_t), "xfs_vnode",
                                        KM_ZONE_HWALIGN | KM_ZONE_RECLAIM |
                                        KM_ZONE_SPREAD,
                                        xfs_fs_inode_init_once);
@@ -409,22 +407,17 @@ xfs_fs_write_inode(
        struct inode            *inode,
        int                     sync)
 {
-       vnode_t                 *vp = vn_from_inode(inode);
+       bhv_vnode_t             *vp = vn_from_inode(inode);
        int                     error = 0, flags = FLUSH_INODE;
 
        if (vp) {
                vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
                if (sync)
                        flags |= FLUSH_SYNC;
-               VOP_IFLUSH(vp, flags, error);
-               if (error == EAGAIN) {
-                       if (sync)
-                               VOP_IFLUSH(vp, flags | FLUSH_LOG, error);
-                       else
-                               error = 0;
-               }
+               error = bhv_vop_iflush(vp, flags);
+               if (error == EAGAIN)
+                       error = sync? bhv_vop_iflush(vp, flags | FLUSH_LOG) : 0;
        }
-
        return -error;
 }
 
@@ -432,8 +425,7 @@ STATIC void
 xfs_fs_clear_inode(
        struct inode            *inode)
 {
-       vnode_t                 *vp = vn_from_inode(inode);
-       int                     error, cache;
+       bhv_vnode_t             *vp = vn_from_inode(inode);
 
        vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
 
@@ -446,20 +438,18 @@ xfs_fs_clear_inode(
         * This can happen because xfs_iget_core calls xfs_idestroy if we
         * find an inode with di_mode == 0 but without IGET_CREATE set.
         */
-       if (vp->v_fbhv)
-               VOP_INACTIVE(vp, NULL, cache);
+       if (VNHEAD(vp))
+               bhv_vop_inactive(vp, NULL);
 
        VN_LOCK(vp);
        vp->v_flag &= ~VMODIFIED;
        VN_UNLOCK(vp, 0);
 
-       if (vp->v_fbhv) {
-               VOP_RECLAIM(vp, error);
-               if (error)
-                       panic("vn_purge: cannot reclaim");
-       }
+       if (VNHEAD(vp))
+               if (bhv_vop_reclaim(vp))
+                       panic("%s: cannot reclaim 0x%p\n", __FUNCTION__, vp);
 
-       ASSERT(vp->v_fbhv == NULL);
+       ASSERT(VNHEAD(vp) == NULL);
 
 #ifdef XFS_VNODE_TRACE
        ktrace_free(vp->v_trace);
@@ -475,13 +465,13 @@ xfs_fs_clear_inode(
  */
 STATIC void
 xfs_syncd_queue_work(
-       struct vfs      *vfs,
+       struct bhv_vfs  *vfs,
        void            *data,
-       void            (*syncer)(vfs_t *, void *))
+       void            (*syncer)(bhv_vfs_t *, void *))
 {
-       vfs_sync_work_t *work;
+       struct bhv_vfs_sync_work *work;
 
-       work = kmem_alloc(sizeof(struct vfs_sync_work), KM_SLEEP);
+       work = kmem_alloc(sizeof(struct bhv_vfs_sync_work), KM_SLEEP);
        INIT_LIST_HEAD(&work->w_list);
        work->w_syncer = syncer;
        work->w_data = data;
@@ -500,7 +490,7 @@ xfs_syncd_queue_work(
  */
 STATIC void
 xfs_flush_inode_work(
-       vfs_t           *vfs,
+       bhv_vfs_t       *vfs,
        void            *inode)
 {
        filemap_flush(((struct inode *)inode)->i_mapping);
@@ -512,7 +502,7 @@ xfs_flush_inode(
        xfs_inode_t     *ip)
 {
        struct inode    *inode = vn_to_inode(XFS_ITOV(ip));
-       struct vfs      *vfs = XFS_MTOVFS(ip->i_mount);
+       struct bhv_vfs  *vfs = XFS_MTOVFS(ip->i_mount);
 
        igrab(inode);
        xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work);
@@ -525,7 +515,7 @@ xfs_flush_inode(
  */
 STATIC void
 xfs_flush_device_work(
-       vfs_t           *vfs,
+       bhv_vfs_t       *vfs,
        void            *inode)
 {
        sync_blockdev(vfs->vfs_super->s_bdev);
@@ -537,7 +527,7 @@ xfs_flush_device(
        xfs_inode_t     *ip)
 {
        struct inode    *inode = vn_to_inode(XFS_ITOV(ip));
-       struct vfs      *vfs = XFS_MTOVFS(ip->i_mount);
+       struct bhv_vfs  *vfs = XFS_MTOVFS(ip->i_mount);
 
        igrab(inode);
        xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work);
@@ -545,16 +535,16 @@ xfs_flush_device(
        xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC);
 }
 
-#define SYNCD_FLAGS    (SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR|SYNC_REFCACHE)
 STATIC void
 vfs_sync_worker(
-       vfs_t           *vfsp,
+       bhv_vfs_t       *vfsp,
        void            *unused)
 {
        int             error;
 
        if (!(vfsp->vfs_flag & VFS_RDONLY))
-               VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error);
+               error = bhv_vfs_sync(vfsp, SYNC_FSDATA | SYNC_BDFLUSH | \
+                                       SYNC_ATTR | SYNC_REFCACHE, NULL);
        vfsp->vfs_sync_seq++;
        wmb();
        wake_up(&vfsp->vfs_wait_single_sync_task);
@@ -565,8 +555,8 @@ xfssyncd(
        void                    *arg)
 {
        long                    timeleft;
-       vfs_t                   *vfsp = (vfs_t *) arg;
-       struct vfs_sync_work    *work, *n;
+       bhv_vfs_t               *vfsp = (bhv_vfs_t *) arg;
+       bhv_vfs_sync_work_t     *work, *n;
        LIST_HEAD               (tmp);
 
        timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10);
@@ -600,7 +590,7 @@ xfssyncd(
                        list_del(&work->w_list);
                        if (work == &vfsp->vfs_sync_work)
                                continue;
-                       kmem_free(work, sizeof(struct vfs_sync_work));
+                       kmem_free(work, sizeof(struct bhv_vfs_sync_work));
                }
        }
 
@@ -609,7 +599,7 @@ xfssyncd(
 
 STATIC int
 xfs_fs_start_syncd(
-       vfs_t                   *vfsp)
+       bhv_vfs_t               *vfsp)
 {
        vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
        vfsp->vfs_sync_work.w_vfs = vfsp;
@@ -621,7 +611,7 @@ xfs_fs_start_syncd(
 
 STATIC void
 xfs_fs_stop_syncd(
-       vfs_t                   *vfsp)
+       bhv_vfs_t               *vfsp)
 {
        kthread_stop(vfsp->vfs_sync_task);
 }
@@ -630,35 +620,26 @@ STATIC void
 xfs_fs_put_super(
        struct super_block      *sb)
 {
-       vfs_t                   *vfsp = vfs_from_sb(sb);
+       bhv_vfs_t               *vfsp = vfs_from_sb(sb);
        int                     error;
 
        xfs_fs_stop_syncd(vfsp);
-       VFS_SYNC(vfsp, SYNC_ATTR|SYNC_DELWRI, NULL, error);
-       if (!error)
-               VFS_UNMOUNT(vfsp, 0, NULL, error);
+       bhv_vfs_sync(vfsp, SYNC_ATTR | SYNC_DELWRI, NULL);
+       error = bhv_vfs_unmount(vfsp, 0, NULL);
        if (error) {
-               printk("XFS unmount got error %d\n", error);
-               printk("%s: vfsp/0x%p left dangling!\n", __FUNCTION__, vfsp);
-               return;
+               printk("XFS: unmount got error=%d\n", error);
+               printk("%s: vfs=0x%p left dangling!\n", __FUNCTION__, vfsp);
+       } else {
+               vfs_deallocate(vfsp);
        }
-
-       vfs_deallocate(vfsp);
 }
 
 STATIC void
 xfs_fs_write_super(
        struct super_block      *sb)
 {
-       vfs_t                   *vfsp = vfs_from_sb(sb);
-       int                     error;
-
-       if (sb->s_flags & MS_RDONLY) {
-               sb->s_dirt = 0; /* paranoia */
-               return;
-       }
-       /* Push the log and superblock a little */
-       VFS_SYNC(vfsp, SYNC_FSDATA, NULL, error);
+       if (!(sb->s_flags & MS_RDONLY))
+               bhv_vfs_sync(vfs_from_sb(sb), SYNC_FSDATA, NULL);
        sb->s_dirt = 0;
 }
 
@@ -667,16 +648,16 @@ xfs_fs_sync_super(
        struct super_block      *sb,
        int                     wait)
 {
-       vfs_t           *vfsp = vfs_from_sb(sb);
-       int             error;
-       int             flags = SYNC_FSDATA;
+       bhv_vfs_t               *vfsp = vfs_from_sb(sb);
+       int                     error;
+       int                     flags;
 
        if (unlikely(sb->s_frozen == SB_FREEZE_WRITE))
                flags = SYNC_QUIESCE;
        else
                flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
 
-       VFS_SYNC(vfsp, flags, NULL, error);
+       error = bhv_vfs_sync(vfsp, flags, NULL);
        sb->s_dirt = 0;
 
        if (unlikely(laptop_mode)) {
@@ -706,11 +687,7 @@ xfs_fs_statfs(
        struct super_block      *sb,
        struct kstatfs          *statp)
 {
-       vfs_t                   *vfsp = vfs_from_sb(sb);
-       int                     error;
-
-       VFS_STATVFS(vfsp, statp, NULL, error);
-       return -error;
+       return -bhv_vfs_statvfs(vfs_from_sb(sb), statp, NULL);
 }
 
 STATIC int
@@ -719,13 +696,13 @@ xfs_fs_remount(
        int                     *flags,
        char                    *options)
 {
-       vfs_t                   *vfsp = vfs_from_sb(sb);
+       bhv_vfs_t               *vfsp = vfs_from_sb(sb);
        struct xfs_mount_args   *args = xfs_args_allocate(sb, 0);
        int                     error;
 
-       VFS_PARSEARGS(vfsp, options, args, 1, error);
+       error = bhv_vfs_parseargs(vfsp, options, args, 1);
        if (!error)
-               VFS_MNTUPDATE(vfsp, flags, args, error);
+               error = bhv_vfs_mntupdate(vfsp, flags, args);
        kmem_free(args, sizeof(*args));
        return -error;
 }
@@ -734,7 +711,7 @@ STATIC void
 xfs_fs_lockfs(
        struct super_block      *sb)
 {
-       VFS_FREEZE(vfs_from_sb(sb));
+       bhv_vfs_freeze(vfs_from_sb(sb));
 }
 
 STATIC int
@@ -742,11 +719,7 @@ xfs_fs_show_options(
        struct seq_file         *m,
        struct vfsmount         *mnt)
 {
-       struct vfs              *vfsp = vfs_from_sb(mnt->mnt_sb);
-       int                     error;
-
-       VFS_SHOWARGS(vfsp, m, error);
-       return error;
+       return -bhv_vfs_showargs(vfs_from_sb(mnt->mnt_sb), m);
 }
 
 STATIC int
@@ -754,11 +727,7 @@ xfs_fs_quotasync(
        struct super_block      *sb,
        int                     type)
 {
-       struct vfs              *vfsp = vfs_from_sb(sb);
-       int                     error;
-
-       VFS_QUOTACTL(vfsp, Q_XQUOTASYNC, 0, (caddr_t)NULL, error);
-       return -error;
+       return -bhv_vfs_quotactl(vfs_from_sb(sb), Q_XQUOTASYNC, 0, NULL);
 }
 
 STATIC int
@@ -766,11 +735,7 @@ xfs_fs_getxstate(
        struct super_block      *sb,
        struct fs_quota_stat    *fqs)
 {
-       struct vfs              *vfsp = vfs_from_sb(sb);
-       int                     error;
-
-       VFS_QUOTACTL(vfsp, Q_XGETQSTAT, 0, (caddr_t)fqs, error);
-       return -error;
+       return -bhv_vfs_quotactl(vfs_from_sb(sb), Q_XGETQSTAT, 0, (caddr_t)fqs);
 }
 
 STATIC int
@@ -779,11 +744,7 @@ xfs_fs_setxstate(
        unsigned int            flags,
        int                     op)
 {
-       struct vfs              *vfsp = vfs_from_sb(sb);
-       int                     error;
-
-       VFS_QUOTACTL(vfsp, op, 0, (caddr_t)&flags, error);
-       return -error;
+       return -bhv_vfs_quotactl(vfs_from_sb(sb), op, 0, (caddr_t)&flags);
 }
 
 STATIC int
@@ -793,13 +754,10 @@ xfs_fs_getxquota(
        qid_t                   id,
        struct fs_disk_quota    *fdq)
 {
-       struct vfs              *vfsp = vfs_from_sb(sb);
-       int                     error, getmode;
-
-       getmode = (type == USRQUOTA) ? Q_XGETQUOTA :
-                ((type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETPQUOTA);
-       VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error);
-       return -error;
+       return -bhv_vfs_quotactl(vfs_from_sb(sb),
+                                (type == USRQUOTA) ? Q_XGETQUOTA :
+                                 ((type == GRPQUOTA) ? Q_XGETGQUOTA :
+                                  Q_XGETPQUOTA), id, (caddr_t)fdq);
 }
 
 STATIC int
@@ -809,13 +767,10 @@ xfs_fs_setxquota(
        qid_t                   id,
        struct fs_disk_quota    *fdq)
 {
-       struct vfs              *vfsp = vfs_from_sb(sb);
-       int                     error, setmode;
-
-       setmode = (type == USRQUOTA) ? Q_XSETQLIM :
-                ((type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETPQLIM);
-       VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error);
-       return -error;
+       return -bhv_vfs_quotactl(vfs_from_sb(sb),
+                                (type == USRQUOTA) ? Q_XSETQLIM :
+                                 ((type == GRPQUOTA) ? Q_XSETGQLIM :
+                                  Q_XSETPQLIM), id, (caddr_t)fdq);
 }
 
 STATIC int
@@ -824,34 +779,32 @@ xfs_fs_fill_super(
        void                    *data,
        int                     silent)
 {
-       vnode_t                 *rootvp;
-       struct vfs              *vfsp = vfs_allocate(sb);
+       struct bhv_vnode        *rootvp;
+       struct bhv_vfs          *vfsp = vfs_allocate(sb);
        struct xfs_mount_args   *args = xfs_args_allocate(sb, silent);
        struct kstatfs          statvfs;
-       int                     error, error2;
+       int                     error;
 
        bhv_insert_all_vfsops(vfsp);
 
-       VFS_PARSEARGS(vfsp, (char *)data, args, 0, error);
+       error = bhv_vfs_parseargs(vfsp, (char *)data, args, 0);
        if (error) {
                bhv_remove_all_vfsops(vfsp, 1);
                goto fail_vfsop;
        }
 
        sb_min_blocksize(sb, BBSIZE);
-#ifdef CONFIG_XFS_EXPORT
        sb->s_export_op = &xfs_export_operations;
-#endif
        sb->s_qcop = &xfs_quotactl_operations;
        sb->s_op = &xfs_super_operations;
 
-       VFS_MOUNT(vfsp, args, NULL, error);
+       error = bhv_vfs_mount(vfsp, args, NULL);
        if (error) {
                bhv_remove_all_vfsops(vfsp, 1);
                goto fail_vfsop;
        }
 
-       VFS_STATVFS(vfsp, &statvfs, NULL, error);
+       error = bhv_vfs_statvfs(vfsp, &statvfs, NULL);
        if (error)
                goto fail_unmount;
 
@@ -863,7 +816,7 @@ xfs_fs_fill_super(
        sb->s_time_gran = 1;
        set_posix_acl_flag(sb);
 
-       VFS_ROOT(vfsp, &rootvp, error);
+       error = bhv_vfs_root(vfsp, &rootvp);
        if (error)
                goto fail_unmount;
 
@@ -892,7 +845,7 @@ fail_vnrele:
        }
 
 fail_unmount:
-       VFS_UNMOUNT(vfsp, 0, NULL, error2);
+       bhv_vfs_unmount(vfsp, 0, NULL);
 
 fail_vfsop:
        vfs_deallocate(vfsp);
index 376b96cb513a782d413b096b1e7e0b0962d285f1..33dd1ca13245544b154e67bc2324b72ff5393571 100644 (file)
@@ -105,7 +105,7 @@ struct block_device;
 
 extern __uint64_t xfs_max_file_offset(unsigned int);
 
-extern void xfs_initialize_vnode(bhv_desc_t *, vnode_t *, bhv_desc_t *, int);
+extern void xfs_initialize_vnode(bhv_desc_t *, bhv_vnode_t *, bhv_desc_t *, int);
 
 extern void xfs_flush_inode(struct xfs_inode *);
 extern void xfs_flush_device(struct xfs_inode *);
index 7079cc8372100aa8b2f7a3c3bd95e708a9a11531..4af97682bec8e066a62e7207ac5440eaaaa0b37f 100644 (file)
@@ -120,6 +120,11 @@ STATIC ctl_table xfs_table[] = {
        &sysctl_intvec, NULL,
        &xfs_params.rotorstep.min, &xfs_params.rotorstep.max},
 
+       {XFS_INHERIT_NODFRG, "inherit_nodefrag", &xfs_params.inherit_nodfrg.val,
+       sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+       &sysctl_intvec, NULL,
+       &xfs_params.inherit_nodfrg.min, &xfs_params.inherit_nodfrg.max},
+
        /* please keep this the last entry */
 #ifdef CONFIG_PROC_FS
        {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val,
index bc8c11f1372203b400dfd62c81bbe2a7b1636803..a631fb8cc5ac4c57ad04e9090184eef58fcec75a 100644 (file)
@@ -46,6 +46,7 @@ typedef struct xfs_param {
        xfs_sysctl_val_t xfs_buf_age;   /* Metadata buffer age before flush. */
        xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */
        xfs_sysctl_val_t rotorstep;     /* inode32 AG rotoring control knob */
+       xfs_sysctl_val_t inherit_nodfrg;/* Inherit the "nodefrag" inode flag. */
 } xfs_param_t;
 
 /*
@@ -84,6 +85,7 @@ enum {
        /* XFS_IO_BYPASS = 18 */
        XFS_INHERIT_NOSYM = 19,
        XFS_ROTORSTEP = 20,
+       XFS_INHERIT_NODFRG = 21,
 };
 
 extern xfs_param_t     xfs_params;
index 6f7c9f7a86246ee1f3e822b5e706417718f77406..6145e8bd0be2f7a34bc95da993acae2ac2bfaa59 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_imap.h"
 #include "xfs_alloc.h"
@@ -104,7 +103,7 @@ vfs_mntupdate(
 int
 vfs_root(
        struct bhv_desc         *bdp,
-       struct vnode            **vpp)
+       struct bhv_vnode        **vpp)
 {
        struct bhv_desc         *next = bdp;
 
@@ -117,15 +116,15 @@ vfs_root(
 int
 vfs_statvfs(
        struct bhv_desc         *bdp,
-       xfs_statfs_t            *sp,
-       struct vnode            *vp)
+       bhv_statvfs_t           *statp,
+       struct bhv_vnode        *vp)
 {
        struct bhv_desc         *next = bdp;
 
        ASSERT(next);
        while (! (bhvtovfsops(next))->vfs_statvfs)
                next = BHV_NEXT(next);
-       return ((*bhvtovfsops(next)->vfs_statvfs)(next, sp, vp));
+       return ((*bhvtovfsops(next)->vfs_statvfs)(next, statp, vp));
 }
 
 int
@@ -145,7 +144,7 @@ vfs_sync(
 int
 vfs_vget(
        struct bhv_desc         *bdp,
-       struct vnode            **vpp,
+       struct bhv_vnode        **vpp,
        struct fid              *fidp)
 {
        struct bhv_desc         *next = bdp;
@@ -187,7 +186,7 @@ vfs_quotactl(
 void
 vfs_init_vnode(
        struct bhv_desc         *bdp,
-       struct vnode            *vp,
+       struct bhv_vnode        *vp,
        struct bhv_desc         *bp,
        int                     unlock)
 {
@@ -226,13 +225,13 @@ vfs_freeze(
        ((*bhvtovfsops(next)->vfs_freeze)(next));
 }
 
-vfs_t *
+bhv_vfs_t *
 vfs_allocate(
        struct super_block      *sb)
 {
-       struct vfs              *vfsp;
+       struct bhv_vfs          *vfsp;
 
-       vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP);
+       vfsp = kmem_zalloc(sizeof(bhv_vfs_t), KM_SLEEP);
        bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
        INIT_LIST_HEAD(&vfsp->vfs_sync_list);
        spin_lock_init(&vfsp->vfs_sync_lock);
@@ -247,25 +246,25 @@ vfs_allocate(
        return vfsp;
 }
 
-vfs_t *
+bhv_vfs_t *
 vfs_from_sb(
        struct super_block      *sb)
 {
-       return (vfs_t *)sb->s_fs_info;
+       return (bhv_vfs_t *)sb->s_fs_info;
 }
 
 void
 vfs_deallocate(
-       struct vfs              *vfsp)
+       struct bhv_vfs          *vfsp)
 {
        bhv_head_destroy(VFS_BHVHEAD(vfsp));
-       kmem_free(vfsp, sizeof(vfs_t));
+       kmem_free(vfsp, sizeof(bhv_vfs_t));
 }
 
 void
 vfs_insertops(
-       struct vfs              *vfsp,
-       struct bhv_vfsops       *vfsops)
+       struct bhv_vfs          *vfsp,
+       struct bhv_module_vfsops *vfsops)
 {
        struct bhv_desc         *bdp;
 
@@ -276,9 +275,9 @@ vfs_insertops(
 
 void
 vfs_insertbhv(
-       struct vfs              *vfsp,
+       struct bhv_vfs          *vfsp,
        struct bhv_desc         *bdp,
-       struct vfsops           *vfsops,
+       struct bhv_vfsops       *vfsops,
        void                    *mount)
 {
        bhv_desc_init(bdp, mount, vfsp, vfsops);
@@ -287,7 +286,7 @@ vfs_insertbhv(
 
 void
 bhv_remove_vfsops(
-       struct vfs              *vfsp,
+       struct bhv_vfs          *vfsp,
        int                     pos)
 {
        struct bhv_desc         *bhv;
@@ -301,7 +300,7 @@ bhv_remove_vfsops(
 
 void
 bhv_remove_all_vfsops(
-       struct vfs              *vfsp,
+       struct bhv_vfs          *vfsp,
        int                     freebase)
 {
        struct xfs_mount        *mp;
@@ -317,7 +316,7 @@ bhv_remove_all_vfsops(
 
 void
 bhv_insert_all_vfsops(
-       struct vfs              *vfsp)
+       struct bhv_vfs          *vfsp)
 {
        struct xfs_mount        *mp;
 
index 841200c030921ff38ac1535e0329c7ae0e69d3e7..91fc2c4b3353f1f4ea96ed51de25ade3f4304f76 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/vfs.h>
 #include "xfs_fs.h"
 
+struct bhv_vfs;
+struct bhv_vnode;
+
 struct fid;
-struct vfs;
 struct cred;
-struct vnode;
-struct kstatfs;
 struct seq_file;
 struct super_block;
 struct xfs_mount_args;
 
-typedef struct kstatfs xfs_statfs_t;
+typedef struct kstatfs bhv_statvfs_t;
 
-typedef struct vfs_sync_work {
+typedef struct bhv_vfs_sync_work {
        struct list_head        w_list;
-       struct vfs              *w_vfs;
+       struct bhv_vfs          *w_vfs;
        void                    *w_data;        /* syncer routine argument */
-       void                    (*w_syncer)(struct vfs *, void *);
-} vfs_sync_work_t;
+       void                    (*w_syncer)(struct bhv_vfs *, void *);
+} bhv_vfs_sync_work_t;
 
-typedef struct vfs {
+typedef struct bhv_vfs {
        u_int                   vfs_flag;       /* flags */
        xfs_fsid_t              vfs_fsid;       /* file system ID */
        xfs_fsid_t              *vfs_altfsid;   /* An ID fixed for life of FS */
        bhv_head_t              vfs_bh;         /* head of vfs behavior chain */
        struct super_block      *vfs_super;     /* generic superblock pointer */
        struct task_struct      *vfs_sync_task; /* generalised sync thread */
-       vfs_sync_work_t         vfs_sync_work;  /* work item for VFS_SYNC */
+       bhv_vfs_sync_work_t     vfs_sync_work;  /* work item for VFS_SYNC */
        struct list_head        vfs_sync_list;  /* sync thread work item list */
        spinlock_t              vfs_sync_lock;  /* work item list lock */
-       int                     vfs_sync_seq;   /* sync thread generation no. */
+       int                     vfs_sync_seq;   /* sync thread generation no. */
        wait_queue_head_t       vfs_wait_single_sync_task;
-} vfs_t;
-
-#define vfs_fbhv               vfs_bh.bh_first /* 1st on vfs behavior chain */
+} bhv_vfs_t;
 
-#define bhvtovfs(bdp)          ( (struct vfs *)BHV_VOBJ(bdp) )
-#define bhvtovfsops(bdp)       ( (struct vfsops *)BHV_OPS(bdp) )
+#define bhvtovfs(bdp)          ( (struct bhv_vfs *)BHV_VOBJ(bdp) )
+#define bhvtovfsops(bdp)       ( (struct bhv_vfsops *)BHV_OPS(bdp) )
 #define VFS_BHVHEAD(vfs)       ( &(vfs)->vfs_bh )
 #define VFS_REMOVEBHV(vfs, bdp)        ( bhv_remove(VFS_BHVHEAD(vfs), bdp) )
 
@@ -71,7 +69,7 @@ typedef enum {
        VFS_BHV_QM,             /* quota manager */
        VFS_BHV_IO,             /* IO path */
        VFS_BHV_END             /* housekeeping end-of-range */
-} vfs_bhv_t;
+} bhv_vfs_type_t;
 
 #define VFS_POSITION_XFS       (BHV_POSITION_BASE)
 #define VFS_POSITION_DM                (VFS_POSITION_BASE+10)
@@ -81,8 +79,9 @@ typedef enum {
 #define VFS_RDONLY             0x0001  /* read-only vfs */
 #define VFS_GRPID              0x0002  /* group-ID assigned from directory */
 #define VFS_DMI                        0x0004  /* filesystem has the DMI enabled */
-#define VFS_32BITINODES                0x0008  /* do not use inums above 32 bits */
-#define VFS_END                        0x0008  /* max flag */
+#define VFS_UMOUNT             0x0008  /* unmount in progress */
+#define VFS_32BITINODES                0x0010  /* do not use inums above 32 bits */
+#define VFS_END                        0x0010  /* max flag */
 
 #define SYNC_ATTR              0x0001  /* sync attributes */
 #define SYNC_CLOSE             0x0002  /* close file system down */
@@ -92,7 +91,14 @@ typedef enum {
 #define SYNC_FSDATA            0x0020  /* flush fs data (e.g. superblocks) */
 #define SYNC_REFCACHE          0x0040  /* prune some of the nfs ref cache */
 #define SYNC_REMOUNT           0x0080  /* remount readonly, no dummy LRs */
-#define SYNC_QUIESCE           0x0100  /* quiesce filesystem for a snapshot */
+#define SYNC_QUIESCE           0x0100  /* quiesce fileystem for a snapshot */
+
+#define SHUTDOWN_META_IO_ERROR 0x0001  /* write attempt to metadata failed */
+#define SHUTDOWN_LOG_IO_ERROR  0x0002  /* write attempt to the log failed */
+#define SHUTDOWN_FORCE_UMOUNT  0x0004  /* shutdown from a forced unmount */
+#define SHUTDOWN_CORRUPT_INCORE        0x0008  /* corrupt in-memory data structures */
+#define SHUTDOWN_REMOTE_REQ    0x0010  /* shutdown came from remote cell */
+#define SHUTDOWN_DEVICE_REQ    0x0020  /* failed all paths to the device */
 
 typedef int    (*vfs_mount_t)(bhv_desc_t *,
                                struct xfs_mount_args *, struct cred *);
@@ -102,18 +108,19 @@ typedef   int     (*vfs_showargs_t)(bhv_desc_t *, struct seq_file *);
 typedef int    (*vfs_unmount_t)(bhv_desc_t *, int, struct cred *);
 typedef int    (*vfs_mntupdate_t)(bhv_desc_t *, int *,
                                struct xfs_mount_args *);
-typedef int    (*vfs_root_t)(bhv_desc_t *, struct vnode **);
-typedef int    (*vfs_statvfs_t)(bhv_desc_t *, xfs_statfs_t *, struct vnode *);
+typedef int    (*vfs_root_t)(bhv_desc_t *, struct bhv_vnode **);
+typedef int    (*vfs_statvfs_t)(bhv_desc_t *, bhv_statvfs_t *,
+                               struct bhv_vnode *);
 typedef int    (*vfs_sync_t)(bhv_desc_t *, int, struct cred *);
-typedef int    (*vfs_vget_t)(bhv_desc_t *, struct vnode **, struct fid *);
+typedef int    (*vfs_vget_t)(bhv_desc_t *, struct bhv_vnode **, struct fid *);
 typedef int    (*vfs_dmapiops_t)(bhv_desc_t *, caddr_t);
 typedef int    (*vfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t);
 typedef void   (*vfs_init_vnode_t)(bhv_desc_t *,
-                               struct vnode *, bhv_desc_t *, int);
+                               struct bhv_vnode *, bhv_desc_t *, int);
 typedef void   (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int);
 typedef void   (*vfs_freeze_t)(bhv_desc_t *);
 
-typedef struct vfsops {
+typedef struct bhv_vfsops {
        bhv_position_t          vf_position;    /* behavior chain position */
        vfs_mount_t             vfs_mount;      /* mount file system */
        vfs_parseargs_t         vfs_parseargs;  /* parse mount options */
@@ -129,82 +136,82 @@ typedef struct vfsops {
        vfs_init_vnode_t        vfs_init_vnode; /* initialize a new vnode */
        vfs_force_shutdown_t    vfs_force_shutdown;     /* crash and burn */
        vfs_freeze_t            vfs_freeze;     /* freeze fs for snapshot */
-} vfsops_t;
+} bhv_vfsops_t;
 
 /*
- * VFS's.  Operates on vfs structure pointers (starts at bhv head).
+ * Virtual filesystem operations, operating from head bhv.
  */
-#define VHEAD(v)                       ((v)->vfs_fbhv)
-#define VFS_MOUNT(v, ma,cr, rv)                ((rv) = vfs_mount(VHEAD(v), ma,cr))
-#define VFS_PARSEARGS(v, o,ma,f, rv)   ((rv) = vfs_parseargs(VHEAD(v), o,ma,f))
-#define VFS_SHOWARGS(v, m, rv)         ((rv) = vfs_showargs(VHEAD(v), m))
-#define VFS_UNMOUNT(v, f, cr, rv)      ((rv) = vfs_unmount(VHEAD(v), f,cr))
-#define VFS_MNTUPDATE(v, fl, args, rv) ((rv) = vfs_mntupdate(VHEAD(v), fl, args))
-#define VFS_ROOT(v, vpp, rv)           ((rv) = vfs_root(VHEAD(v), vpp))
-#define VFS_STATVFS(v, sp,vp, rv)      ((rv) = vfs_statvfs(VHEAD(v), sp,vp))
-#define VFS_SYNC(v, flag,cr, rv)       ((rv) = vfs_sync(VHEAD(v), flag,cr))
-#define VFS_VGET(v, vpp,fidp, rv)      ((rv) = vfs_vget(VHEAD(v), vpp,fidp))
-#define VFS_DMAPIOPS(v, p, rv)         ((rv) = vfs_dmapiops(VHEAD(v), p))
-#define VFS_QUOTACTL(v, c,id,p, rv)    ((rv) = vfs_quotactl(VHEAD(v), c,id,p))
-#define VFS_INIT_VNODE(v, vp,b,ul)     ( vfs_init_vnode(VHEAD(v), vp,b,ul) )
-#define VFS_FORCE_SHUTDOWN(v, fl,f,l)  ( vfs_force_shutdown(VHEAD(v), fl,f,l) )
-#define VFS_FREEZE(v)                  ( vfs_freeze(VHEAD(v)) )
+#define VFSHEAD(v)                     ((v)->vfs_bh.bh_first)
+#define bhv_vfs_mount(v, ma,cr)                vfs_mount(VFSHEAD(v), ma,cr)
+#define bhv_vfs_parseargs(v, o,ma,f)   vfs_parseargs(VFSHEAD(v), o,ma,f)
+#define bhv_vfs_showargs(v, m)         vfs_showargs(VFSHEAD(v), m)
+#define bhv_vfs_unmount(v, f,cr)       vfs_unmount(VFSHEAD(v), f,cr)
+#define bhv_vfs_mntupdate(v, fl,args)  vfs_mntupdate(VFSHEAD(v), fl,args)
+#define bhv_vfs_root(v, vpp)           vfs_root(VFSHEAD(v), vpp)
+#define bhv_vfs_statvfs(v, sp,vp)      vfs_statvfs(VFSHEAD(v), sp,vp)
+#define bhv_vfs_sync(v, flag,cr)       vfs_sync(VFSHEAD(v), flag,cr)
+#define bhv_vfs_vget(v, vpp,fidp)      vfs_vget(VFSHEAD(v), vpp,fidp)
+#define bhv_vfs_dmapiops(v, p)         vfs_dmapiops(VFSHEAD(v), p)
+#define bhv_vfs_quotactl(v, c,id,p)    vfs_quotactl(VFSHEAD(v), c,id,p)
+#define bhv_vfs_init_vnode(v, vp,b,ul) vfs_init_vnode(VFSHEAD(v), vp,b,ul)
+#define bhv_vfs_force_shutdown(v,u,f,l)        vfs_force_shutdown(VFSHEAD(v), u,f,l)
+#define bhv_vfs_freeze(v)              vfs_freeze(VFSHEAD(v))
 
 /*
- * PVFS's.  Operates on behavior descriptor pointers.
+ * Virtual filesystem operations, operating from next bhv.
  */
-#define PVFS_MOUNT(b, ma,cr, rv)       ((rv) = vfs_mount(b, ma,cr))
-#define PVFS_PARSEARGS(b, o,ma,f, rv)  ((rv) = vfs_parseargs(b, o,ma,f))
-#define PVFS_SHOWARGS(b, m, rv)                ((rv) = vfs_showargs(b, m))
-#define PVFS_UNMOUNT(b, f,cr, rv)      ((rv) = vfs_unmount(b, f,cr))
-#define PVFS_MNTUPDATE(b, fl, args, rv)        ((rv) = vfs_mntupdate(b, fl, args))
-#define PVFS_ROOT(b, vpp, rv)          ((rv) = vfs_root(b, vpp))
-#define PVFS_STATVFS(b, sp,vp, rv)     ((rv) = vfs_statvfs(b, sp,vp))
-#define PVFS_SYNC(b, flag,cr, rv)      ((rv) = vfs_sync(b, flag,cr))
-#define PVFS_VGET(b, vpp,fidp, rv)     ((rv) = vfs_vget(b, vpp,fidp))
-#define PVFS_DMAPIOPS(b, p, rv)                ((rv) = vfs_dmapiops(b, p))
-#define PVFS_QUOTACTL(b, c,id,p, rv)   ((rv) = vfs_quotactl(b, c,id,p))
-#define PVFS_INIT_VNODE(b, vp,b2,ul)   ( vfs_init_vnode(b, vp,b2,ul) )
-#define PVFS_FORCE_SHUTDOWN(b, fl,f,l) ( vfs_force_shutdown(b, fl,f,l) )
-#define PVFS_FREEZE(b)                 ( vfs_freeze(b) )
+#define bhv_next_vfs_mount(b, ma,cr)           vfs_mount(b, ma,cr)
+#define bhv_next_vfs_parseargs(b, o,ma,f)      vfs_parseargs(b, o,ma,f)
+#define bhv_next_vfs_showargs(b, m)            vfs_showargs(b, m)
+#define bhv_next_vfs_unmount(b, f,cr)          vfs_unmount(b, f,cr)
+#define bhv_next_vfs_mntupdate(b, fl,args)     vfs_mntupdate(b, fl, args)
+#define bhv_next_vfs_root(b, vpp)              vfs_root(b, vpp)
+#define bhv_next_vfs_statvfs(b, sp,vp)         vfs_statvfs(b, sp,vp)
+#define bhv_next_vfs_sync(b, flag,cr)          vfs_sync(b, flag,cr)
+#define bhv_next_vfs_vget(b, vpp,fidp)         vfs_vget(b, vpp,fidp)
+#define bhv_next_vfs_dmapiops(b, p)            vfs_dmapiops(b, p)
+#define bhv_next_vfs_quotactl(b, c,id,p)       vfs_quotactl(b, c,id,p)
+#define bhv_next_vfs_init_vnode(b, vp,b2,ul)   vfs_init_vnode(b, vp,b2,ul)
+#define bhv_next_force_shutdown(b, fl,f,l)     vfs_force_shutdown(b, fl,f,l)
+#define bhv_next_vfs_freeze(b)                 vfs_freeze(b)
 
 extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *);
 extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int);
 extern int vfs_showargs(bhv_desc_t *, struct seq_file *);
 extern int vfs_unmount(bhv_desc_t *, int, struct cred *);
 extern int vfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *);
-extern int vfs_root(bhv_desc_t *, struct vnode **);
-extern int vfs_statvfs(bhv_desc_t *, xfs_statfs_t *, struct vnode *);
+extern int vfs_root(bhv_desc_t *, struct bhv_vnode **);
+extern int vfs_statvfs(bhv_desc_t *, bhv_statvfs_t *, struct bhv_vnode *);
 extern int vfs_sync(bhv_desc_t *, int, struct cred *);
-extern int vfs_vget(bhv_desc_t *, struct vnode **, struct fid *);
+extern int vfs_vget(bhv_desc_t *, struct bhv_vnode **, struct fid *);
 extern int vfs_dmapiops(bhv_desc_t *, caddr_t);
 extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t);
-extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int);
+extern void vfs_init_vnode(bhv_desc_t *, struct bhv_vnode *, bhv_desc_t *, int);
 extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int);
 extern void vfs_freeze(bhv_desc_t *);
 
-typedef struct bhv_vfsops {
-       struct vfsops           bhv_common;
+#define vfs_test_for_freeze(vfs)       ((vfs)->vfs_super->s_frozen)
+#define vfs_wait_for_freeze(vfs,l)     vfs_check_frozen((vfs)->vfs_super, (l))
+typedef struct bhv_module_vfsops {
+       struct bhv_vfsops       bhv_common;
        void *                  bhv_custom;
-} bhv_vfsops_t;
+} bhv_module_vfsops_t;
 
-#define vfs_bhv_lookup(v, id)  ( bhv_lookup_range(&(v)->vfs_bh, (id), (id)) )
-#define vfs_bhv_custom(b)      ( ((bhv_vfsops_t *)BHV_OPS(b))->bhv_custom )
-#define vfs_bhv_set_custom(b,o)        ( (b)->bhv_custom = (void *)(o))
-#define vfs_bhv_clr_custom(b)  ( (b)->bhv_custom = NULL )
+#define vfs_bhv_lookup(v, id)  (bhv_lookup_range(&(v)->vfs_bh, (id), (id)))
+#define vfs_bhv_custom(b)      (((bhv_module_vfsops_t*)BHV_OPS(b))->bhv_custom)
+#define vfs_bhv_set_custom(b,o)        ((b)->bhv_custom = (void *)(o))
+#define vfs_bhv_clr_custom(b)  ((b)->bhv_custom = NULL)
 
-extern vfs_t *vfs_allocate(struct super_block *);
-extern vfs_t *vfs_from_sb(struct super_block *);
-extern void vfs_deallocate(vfs_t *);
-extern void vfs_insertops(vfs_t *, bhv_vfsops_t *);
-extern void vfs_insertbhv(vfs_t *, bhv_desc_t *, vfsops_t *, void *);
+extern bhv_vfs_t *vfs_allocate(struct super_block *);
+extern bhv_vfs_t *vfs_from_sb(struct super_block *);
+extern void vfs_deallocate(bhv_vfs_t *);
+extern void vfs_insertbhv(bhv_vfs_t *, bhv_desc_t *, bhv_vfsops_t *, void *);
 
-extern void bhv_insert_all_vfsops(struct vfs *);
-extern void bhv_remove_all_vfsops(struct vfs *, int);
-extern void bhv_remove_vfsops(struct vfs *, int);
+extern void vfs_insertops(bhv_vfs_t *, bhv_module_vfsops_t *);
 
-#define fs_frozen(vfsp)                ((vfsp)->vfs_super->s_frozen)
-#define fs_check_frozen(vfsp, level) \
-       vfs_check_frozen(vfsp->vfs_super, level);
+extern void bhv_insert_all_vfsops(struct bhv_vfs *);
+extern void bhv_remove_all_vfsops(struct bhv_vfs *, int);
+extern void bhv_remove_vfsops(struct bhv_vfs *, int);
 
 #endif /* __XFS_VFS_H__ */
index d27c25b27ccd4aec1e4f8c8d235e7f41b07034dd..6628d96b6fd6a02cfba135c50976ff154def34bc 100644 (file)
@@ -39,7 +39,7 @@ vn_init(void)
 
 void
 vn_iowait(
-       struct vnode    *vp)
+       bhv_vnode_t     *vp)
 {
        wait_queue_head_t *wq = vptosync(vp);
 
@@ -48,17 +48,33 @@ vn_iowait(
 
 void
 vn_iowake(
-       struct vnode    *vp)
+       bhv_vnode_t     *vp)
 {
        if (atomic_dec_and_test(&vp->v_iocount))
                wake_up(vptosync(vp));
 }
 
-struct vnode *
+/*
+ * Volume managers supporting multiple paths can send back ENODEV when the
+ * final path disappears.  In this case continuing to fill the page cache
+ * with dirty data which cannot be written out is evil, so prevent that.
+ */
+void
+vn_ioerror(
+       bhv_vnode_t     *vp,
+       int             error,
+       char            *f,
+       int             l)
+{
+       if (unlikely(error == -ENODEV))
+               bhv_vfs_force_shutdown(vp->v_vfsp, SHUTDOWN_DEVICE_REQ, f, l);
+}
+
+bhv_vnode_t *
 vn_initialize(
        struct inode    *inode)
 {
-       struct vnode    *vp = vn_from_inode(inode);
+       bhv_vnode_t     *vp = vn_from_inode(inode);
 
        XFS_STATS_INC(vn_active);
        XFS_STATS_INC(vn_alloc);
@@ -94,8 +110,8 @@ vn_initialize(
  */
 void
 vn_revalidate_core(
-       struct vnode    *vp,
-       vattr_t         *vap)
+       bhv_vnode_t     *vp,
+       bhv_vattr_t     *vap)
 {
        struct inode    *inode = vn_to_inode(vp);
 
@@ -130,14 +146,14 @@ vn_revalidate_core(
  */
 int
 __vn_revalidate(
-       struct vnode    *vp,
-       struct vattr    *vattr)
+       bhv_vnode_t     *vp,
+       bhv_vattr_t     *vattr)
 {
        int             error;
 
        vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
        vattr->va_mask = XFS_AT_STAT | XFS_AT_XFLAGS;
-       VOP_GETATTR(vp, vattr, 0, NULL, error);
+       error = bhv_vop_getattr(vp, vattr, 0, NULL);
        if (likely(!error)) {
                vn_revalidate_core(vp, vattr);
                VUNMODIFY(vp);
@@ -147,9 +163,9 @@ __vn_revalidate(
 
 int
 vn_revalidate(
-       struct vnode    *vp)
+       bhv_vnode_t     *vp)
 {
-       vattr_t         vattr;
+       bhv_vattr_t     vattr;
 
        return __vn_revalidate(vp, &vattr);
 }
@@ -157,9 +173,9 @@ vn_revalidate(
 /*
  * Add a reference to a referenced vnode.
  */
-struct vnode *
+bhv_vnode_t *
 vn_hold(
-       struct vnode    *vp)
+       bhv_vnode_t     *vp)
 {
        struct inode    *inode;
 
@@ -192,31 +208,31 @@ vn_hold(
  * Vnode tracing code.
  */
 void
-vn_trace_entry(vnode_t *vp, const char *func, inst_t *ra)
+vn_trace_entry(bhv_vnode_t *vp, const char *func, inst_t *ra)
 {
        KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra);
 }
 
 void
-vn_trace_exit(vnode_t *vp, const char *func, inst_t *ra)
+vn_trace_exit(bhv_vnode_t *vp, const char *func, inst_t *ra)
 {
        KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra);
 }
 
 void
-vn_trace_hold(vnode_t *vp, char *file, int line, inst_t *ra)
+vn_trace_hold(bhv_vnode_t *vp, char *file, int line, inst_t *ra)
 {
        KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra);
 }
 
 void
-vn_trace_ref(vnode_t *vp, char *file, int line, inst_t *ra)
+vn_trace_ref(bhv_vnode_t *vp, char *file, int line, inst_t *ra)
 {
        KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra);
 }
 
 void
-vn_trace_rele(vnode_t *vp, char *file, int line, inst_t *ra)
+vn_trace_rele(bhv_vnode_t *vp, char *file, int line, inst_t *ra)
 {
        KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra);
 }
index 2a8e16c22353c98f44a12bc462130a43c2646555..35c6a01963a77c9c52af0ba70453926aab316f04 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write the Free Software Foundation,
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * Portions Copyright (c) 1989, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
  */
 #ifndef __XFS_VNODE_H__
 #define __XFS_VNODE_H__
 
 struct uio;
 struct file;
-struct vattr;
+struct bhv_vfs;
+struct bhv_vattr;
 struct xfs_iomap;
 struct attrlist_cursor_kern;
 
+typedef struct dentry  bhv_vname_t;
+typedef __u64          bhv_vnumber_t;
 
-typedef xfs_ino_t vnumber_t;
-typedef struct dentry vname_t;
-typedef bhv_head_t vn_bhv_head_t;
+typedef enum bhv_vflags {
+       VMODIFIED       = 0x08, /* XFS inode state possibly differs */
+                               /* to the Linux inode state. */
+       VTRUNCATED      = 0x40, /* truncated down so flush-on-close */
+} bhv_vflags_t;
 
 /*
  * MP locking protocols:
  *     v_flag, v_vfsp                          VN_LOCK/VN_UNLOCK
  */
-typedef struct vnode {
-       __u32           v_flag;                 /* vnode flags (see below) */
-       struct vfs      *v_vfsp;                /* ptr to containing VFS */
-       vnumber_t       v_number;               /* in-core vnode number */
-       vn_bhv_head_t   v_bh;                   /* behavior head */
+typedef struct bhv_vnode {
+       bhv_vflags_t    v_flag;                 /* vnode flags (see above) */
+       bhv_vfs_t       *v_vfsp;                /* ptr to containing VFS */
+       bhv_vnumber_t   v_number;               /* in-core vnode number */
+       bhv_head_t      v_bh;                   /* behavior head */
        spinlock_t      v_lock;                 /* VN_LOCK/VN_UNLOCK */
        atomic_t        v_iocount;              /* outstanding I/O count */
 #ifdef XFS_VNODE_TRACE
@@ -72,7 +50,7 @@ typedef struct vnode {
 #endif
        struct inode    v_inode;                /* Linux inode */
        /* inode MUST be last */
-} vnode_t;
+} bhv_vnode_t;
 
 #define VN_ISLNK(vp)   S_ISLNK((vp)->v_inode.i_mode)
 #define VN_ISREG(vp)   S_ISREG((vp)->v_inode.i_mode)
@@ -80,9 +58,6 @@ typedef struct vnode {
 #define VN_ISCHR(vp)   S_ISCHR((vp)->v_inode.i_mode)
 #define VN_ISBLK(vp)   S_ISBLK((vp)->v_inode.i_mode)
 
-#define v_fbhv                 v_bh.bh_first          /* first behavior */
-#define v_fops                 v_bh.bh_first->bd_ops  /* first behavior ops */
-
 #define VNODE_POSITION_BASE    BHV_POSITION_BASE       /* chain bottom */
 #define VNODE_POSITION_TOP     BHV_POSITION_TOP        /* chain top */
 #define VNODE_POSITION_INVALID BHV_POSITION_INVALID    /* invalid pos. num */
@@ -104,8 +79,8 @@ typedef enum {
 /*
  * Macros for dealing with the behavior descriptor inside of the vnode.
  */
-#define BHV_TO_VNODE(bdp)      ((vnode_t *)BHV_VOBJ(bdp))
-#define BHV_TO_VNODE_NULL(bdp) ((vnode_t *)BHV_VOBJNULL(bdp))
+#define BHV_TO_VNODE(bdp)      ((bhv_vnode_t *)BHV_VOBJ(bdp))
+#define BHV_TO_VNODE_NULL(bdp) ((bhv_vnode_t *)BHV_VOBJNULL(bdp))
 
 #define VN_BHV_HEAD(vp)                        ((bhv_head_t *)(&((vp)->v_bh)))
 #define vn_bhv_head_init(bhp,name)     bhv_head_init(bhp,name)
@@ -116,35 +91,29 @@ typedef enum {
 /*
  * Vnode to Linux inode mapping.
  */
-static inline struct vnode *vn_from_inode(struct inode *inode)
+static inline struct bhv_vnode *vn_from_inode(struct inode *inode)
 {
-       return (vnode_t *)list_entry(inode, vnode_t, v_inode);
+       return (bhv_vnode_t *)list_entry(inode, bhv_vnode_t, v_inode);
 }
-static inline struct inode *vn_to_inode(struct vnode *vnode)
+static inline struct inode *vn_to_inode(struct bhv_vnode *vnode)
 {
        return &vnode->v_inode;
 }
 
 /*
- * Vnode flags.
- */
-#define VMODIFIED             0x8      /* XFS inode state possibly differs */
-                                       /* to the Linux inode state.    */
-
-/*
- * Values for the VOP_RWLOCK and VOP_RWUNLOCK flags parameter.
+ * Values for the vop_rwlock/rwunlock flags parameter.
  */
-typedef enum vrwlock {
+typedef enum bhv_vrwlock {
        VRWLOCK_NONE,
        VRWLOCK_READ,
        VRWLOCK_WRITE,
        VRWLOCK_WRITE_DIRECT,
        VRWLOCK_TRY_READ,
        VRWLOCK_TRY_WRITE
-} vrwlock_t;
+} bhv_vrwlock_t;
 
 /*
- * Return values for VOP_INACTIVE.  A return value of
+ * Return values for bhv_vop_inactive.  A return value of
  * VN_INACTIVE_NOCACHE implies that the file system behavior
  * has disassociated its state and bhv_desc_t from the vnode.
  */
@@ -152,18 +121,20 @@ typedef enum vrwlock {
 #define        VN_INACTIVE_NOCACHE     1
 
 /*
- * Values for the cmd code given to VOP_VNODE_CHANGE.
+ * Values for the cmd code given to vop_vnode_change.
  */
-typedef enum vchange {
+typedef enum bhv_vchange {
        VCHANGE_FLAGS_FRLOCKS           = 0,
        VCHANGE_FLAGS_ENF_LOCKING       = 1,
        VCHANGE_FLAGS_TRUNCATED         = 2,
        VCHANGE_FLAGS_PAGE_DIRTY        = 3,
        VCHANGE_FLAGS_IOEXCL_COUNT      = 4
-} vchange_t;
+} bhv_vchange_t;
 
+typedef enum { L_FALSE, L_TRUE } lastclose_t;
 
 typedef int    (*vop_open_t)(bhv_desc_t *, struct cred *);
+typedef int    (*vop_close_t)(bhv_desc_t *, int, lastclose_t, struct cred *);
 typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *,
                                const struct iovec *, unsigned int,
                                loff_t *, int, struct cred *);
@@ -181,27 +152,27 @@ typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *,
                                struct cred *);
 typedef int    (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *,
                                int, unsigned int, void __user *);
-typedef int    (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int,
+typedef int    (*vop_getattr_t)(bhv_desc_t *, struct bhv_vattr *, int,
                                struct cred *);
-typedef int    (*vop_setattr_t)(bhv_desc_t *, struct vattr *, int,
+typedef int    (*vop_setattr_t)(bhv_desc_t *, struct bhv_vattr *, int,
                                struct cred *);
 typedef int    (*vop_access_t)(bhv_desc_t *, int, struct cred *);
-typedef int    (*vop_lookup_t)(bhv_desc_t *, vname_t *, vnode_t **,
-                               int, vnode_t *, struct cred *);
-typedef int    (*vop_create_t)(bhv_desc_t *, vname_t *, struct vattr *,
-                               vnode_t **, struct cred *);
-typedef int    (*vop_remove_t)(bhv_desc_t *, vname_t *, struct cred *);
-typedef int    (*vop_link_t)(bhv_desc_t *, vnode_t *, vname_t *,
-                               struct cred *);
-typedef int    (*vop_rename_t)(bhv_desc_t *, vname_t *, vnode_t *, vname_t *,
+typedef int    (*vop_lookup_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t **,
+                               int, bhv_vnode_t *, struct cred *);
+typedef int    (*vop_create_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *,
+                               bhv_vnode_t **, struct cred *);
+typedef int    (*vop_remove_t)(bhv_desc_t *, bhv_vname_t *, struct cred *);
+typedef int    (*vop_link_t)(bhv_desc_t *, bhv_vnode_t *, bhv_vname_t *,
                                struct cred *);
-typedef int    (*vop_mkdir_t)(bhv_desc_t *, vname_t *, struct vattr *,
-                               vnode_t **, struct cred *);
-typedef int    (*vop_rmdir_t)(bhv_desc_t *, vname_t *, struct cred *);
+typedef int    (*vop_rename_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *,
+                               bhv_vname_t *, struct cred *);
+typedef int    (*vop_mkdir_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *,
+                               bhv_vnode_t **, struct cred *);
+typedef int    (*vop_rmdir_t)(bhv_desc_t *, bhv_vname_t *, struct cred *);
 typedef int    (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *,
                                int *);
-typedef int    (*vop_symlink_t)(bhv_desc_t *, vname_t *, struct vattr *,
-                               char *, vnode_t **, struct cred *);
+typedef int    (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*,
+                               char *, bhv_vnode_t **, struct cred *);
 typedef int    (*vop_readlink_t)(bhv_desc_t *, struct uio *, int,
                                struct cred *);
 typedef int    (*vop_fsync_t)(bhv_desc_t *, int, struct cred *,
@@ -209,8 +180,8 @@ typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *,
 typedef int    (*vop_inactive_t)(bhv_desc_t *, struct cred *);
 typedef int    (*vop_fid2_t)(bhv_desc_t *, struct fid *);
 typedef int    (*vop_release_t)(bhv_desc_t *);
-typedef int    (*vop_rwlock_t)(bhv_desc_t *, vrwlock_t);
-typedef void   (*vop_rwunlock_t)(bhv_desc_t *, vrwlock_t);
+typedef int    (*vop_rwlock_t)(bhv_desc_t *, bhv_vrwlock_t);
+typedef void   (*vop_rwunlock_t)(bhv_desc_t *, bhv_vrwlock_t);
 typedef int    (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int,
                                struct xfs_iomap *, int *);
 typedef int    (*vop_reclaim_t)(bhv_desc_t *);
@@ -222,8 +193,8 @@ typedef     int     (*vop_attr_remove_t)(bhv_desc_t *, const char *,
                                int, struct cred *);
 typedef        int     (*vop_attr_list_t)(bhv_desc_t *, char *, int, int,
                                struct attrlist_cursor_kern *, struct cred *);
-typedef void   (*vop_link_removed_t)(bhv_desc_t *, vnode_t *, int);
-typedef void   (*vop_vnode_change_t)(bhv_desc_t *, vchange_t, __psint_t);
+typedef void   (*vop_link_removed_t)(bhv_desc_t *, bhv_vnode_t *, int);
+typedef void   (*vop_vnode_change_t)(bhv_desc_t *, bhv_vchange_t, __psint_t);
 typedef void   (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
 typedef void   (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
 typedef int    (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t,
@@ -231,9 +202,10 @@ typedef int        (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t,
 typedef int    (*vop_iflush_t)(bhv_desc_t *, int);
 
 
-typedef struct vnodeops {
+typedef struct bhv_vnodeops {
        bhv_position_t  vn_position;    /* position within behavior chain */
        vop_open_t              vop_open;
+       vop_close_t             vop_close;
        vop_read_t              vop_read;
        vop_write_t             vop_write;
        vop_sendfile_t          vop_sendfile;
@@ -271,103 +243,80 @@ typedef struct vnodeops {
        vop_pflushvp_t          vop_flush_pages;
        vop_release_t           vop_release;
        vop_iflush_t            vop_iflush;
-} vnodeops_t;
+} bhv_vnodeops_t;
 
 /*
- * VOP's.
- */
-#define _VOP_(op, vp)  (*((vnodeops_t *)(vp)->v_fops)->op)
-
-#define VOP_READ(vp,file,iov,segs,offset,ioflags,cr,rv)                        \
-       rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr)
-#define VOP_WRITE(vp,file,iov,segs,offset,ioflags,cr,rv)               \
-       rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr)
-#define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv)              \
-       rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr)
-#define VOP_SPLICE_READ(vp,f,o,pipe,cnt,fl,iofl,cr,rv)                 \
-       rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr)
-#define VOP_SPLICE_WRITE(vp,f,o,pipe,cnt,fl,iofl,cr,rv)                        \
-       rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr)
-#define VOP_BMAP(vp,of,sz,rw,b,n,rv)                                   \
-       rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n)
-#define VOP_OPEN(vp, cr, rv)                                           \
-       rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr)
-#define VOP_GETATTR(vp, vap, f, cr, rv)                                        \
-       rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr)
-#define        VOP_SETATTR(vp, vap, f, cr, rv)                                 \
-       rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr)
-#define        VOP_ACCESS(vp, mode, cr, rv)                                    \
-       rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr)
-#define        VOP_LOOKUP(vp,d,vpp,f,rdir,cr,rv)                               \
-       rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr)
-#define VOP_CREATE(dvp,d,vap,vpp,cr,rv)                                        \
-       rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr)
-#define VOP_REMOVE(dvp,d,cr,rv)                                                \
-       rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr)
-#define        VOP_LINK(tdvp,fvp,d,cr,rv)                                      \
-       rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr)
-#define        VOP_RENAME(fvp,fnm,tdvp,tnm,cr,rv)                              \
-       rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr)
-#define        VOP_MKDIR(dp,d,vap,vpp,cr,rv)                                   \
-       rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr)
-#define        VOP_RMDIR(dp,d,cr,rv)                                           \
-       rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr)
-#define        VOP_READDIR(vp,uiop,cr,eofp,rv)                                 \
-       rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp)
-#define        VOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv)                            \
-       rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr)
-#define        VOP_READLINK(vp,uiop,fl,cr,rv)                                  \
-       rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,fl,cr)
-#define        VOP_FSYNC(vp,f,cr,b,e,rv)                                       \
-       rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e)
-#define VOP_INACTIVE(vp, cr, rv)                                       \
-       rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr)
-#define VOP_RELEASE(vp, rv)                                            \
-       rv = _VOP_(vop_release, vp)((vp)->v_fbhv)
-#define VOP_FID2(vp, fidp, rv)                                         \
-       rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp)
-#define VOP_RWLOCK(vp,i)                                               \
-       (void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
-#define VOP_RWLOCK_TRY(vp,i)                                           \
-       _VOP_(vop_rwlock, vp)((vp)->v_fbhv, i)
-#define VOP_RWUNLOCK(vp,i)                                             \
-       (void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i)
-#define VOP_FRLOCK(vp,c,fl,flags,offset,fr,rv)                         \
-       rv = _VOP_(vop_frlock, vp)((vp)->v_fbhv,c,fl,flags,offset,fr)
-#define VOP_RECLAIM(vp, rv)                                            \
-       rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv)
-#define VOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv)             \
-       rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred)
-#define        VOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv)               \
-       rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred)
-#define        VOP_ATTR_REMOVE(vp, name, flags, cred, rv)                      \
-       rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred)
-#define        VOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv)            \
-       rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred)
-#define VOP_LINK_REMOVED(vp, dvp, linkzero)                            \
-       (void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero)
-#define VOP_VNODE_CHANGE(vp, cmd, val)                                 \
-       (void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val)
-/*
- * These are page cache functions that now go thru VOPs.
- * 'last' parameter is unused and left in for IRIX compatibility
+ * Virtual node operations, operating from head bhv.
  */
-#define VOP_TOSS_PAGES(vp, first, last, fiopt)                         \
-       _VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt)
-/*
- * 'last' parameter is unused and left in for IRIX compatibility
- */
-#define VOP_FLUSHINVAL_PAGES(vp, first, last, fiopt)                   \
-       _VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt)
-/*
- * 'last' parameter is unused and left in for IRIX compatibility
- */
-#define VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv)             \
-       rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt)
-#define VOP_IOCTL(vp, inode, filp, fl, cmd, arg, rv)                   \
-       rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,fl,cmd,arg)
-#define VOP_IFLUSH(vp, flags, rv)                                      \
-       rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags)
+#define VNHEAD(vp)     ((vp)->v_bh.bh_first)
+#define VOP(op, vp)    (*((bhv_vnodeops_t *)VNHEAD(vp)->bd_ops)->op)
+#define bhv_vop_open(vp, cr)           VOP(vop_open, vp)(VNHEAD(vp),cr)
+#define bhv_vop_close(vp, f,last,cr)   VOP(vop_close, vp)(VNHEAD(vp),f,last,cr)
+#define bhv_vop_read(vp,file,iov,segs,offset,ioflags,cr)               \
+               VOP(vop_read, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr)
+#define bhv_vop_write(vp,file,iov,segs,offset,ioflags,cr)              \
+               VOP(vop_write, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr)
+#define bhv_vop_sendfile(vp,f,off,ioflags,cnt,act,targ,cr)             \
+               VOP(vop_sendfile, vp)(VNHEAD(vp),f,off,ioflags,cnt,act,targ,cr)
+#define bhv_vop_splice_read(vp,f,o,pipe,cnt,fl,iofl,cr)                        \
+               VOP(vop_splice_read, vp)(VNHEAD(vp),f,o,pipe,cnt,fl,iofl,cr)
+#define bhv_vop_splice_write(vp,f,o,pipe,cnt,fl,iofl,cr)               \
+               VOP(vop_splice_write, vp)(VNHEAD(vp),f,o,pipe,cnt,fl,iofl,cr)
+#define bhv_vop_bmap(vp,of,sz,rw,b,n)                                  \
+               VOP(vop_bmap, vp)(VNHEAD(vp),of,sz,rw,b,n)
+#define bhv_vop_getattr(vp, vap,f,cr)                                  \
+               VOP(vop_getattr, vp)(VNHEAD(vp), vap,f,cr)
+#define        bhv_vop_setattr(vp, vap,f,cr)                                   \
+               VOP(vop_setattr, vp)(VNHEAD(vp), vap,f,cr)
+#define        bhv_vop_access(vp, mode,cr)     VOP(vop_access, vp)(VNHEAD(vp), mode,cr)
+#define        bhv_vop_lookup(vp,d,vpp,f,rdir,cr)                              \
+               VOP(vop_lookup, vp)(VNHEAD(vp),d,vpp,f,rdir,cr)
+#define bhv_vop_create(dvp,d,vap,vpp,cr)                               \
+               VOP(vop_create, dvp)(VNHEAD(dvp),d,vap,vpp,cr)
+#define bhv_vop_remove(dvp,d,cr)       VOP(vop_remove, dvp)(VNHEAD(dvp),d,cr)
+#define        bhv_vop_link(dvp,fvp,d,cr)      VOP(vop_link, dvp)(VNHEAD(dvp),fvp,d,cr)
+#define        bhv_vop_rename(fvp,fnm,tdvp,tnm,cr)                             \
+               VOP(vop_rename, fvp)(VNHEAD(fvp),fnm,tdvp,tnm,cr)
+#define        bhv_vop_mkdir(dp,d,vap,vpp,cr)                                  \
+               VOP(vop_mkdir, dp)(VNHEAD(dp),d,vap,vpp,cr)
+#define        bhv_vop_rmdir(dp,d,cr)          VOP(vop_rmdir, dp)(VNHEAD(dp),d,cr)
+#define        bhv_vop_readdir(vp,uiop,cr,eofp)                                \
+               VOP(vop_readdir, vp)(VNHEAD(vp),uiop,cr,eofp)
+#define        bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr)                           \
+               VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr)
+#define        bhv_vop_readlink(vp,uiop,fl,cr)                                 \
+               VOP(vop_readlink, vp)(VNHEAD(vp),uiop,fl,cr)
+#define        bhv_vop_fsync(vp,f,cr,b,e)      VOP(vop_fsync, vp)(VNHEAD(vp),f,cr,b,e)
+#define bhv_vop_inactive(vp,cr)                VOP(vop_inactive, vp)(VNHEAD(vp),cr)
+#define bhv_vop_release(vp)            VOP(vop_release, vp)(VNHEAD(vp))
+#define bhv_vop_fid2(vp,fidp)          VOP(vop_fid2, vp)(VNHEAD(vp),fidp)
+#define bhv_vop_rwlock(vp,i)           VOP(vop_rwlock, vp)(VNHEAD(vp),i)
+#define bhv_vop_rwlock_try(vp,i)       VOP(vop_rwlock, vp)(VNHEAD(vp),i)
+#define bhv_vop_rwunlock(vp,i)         VOP(vop_rwunlock, vp)(VNHEAD(vp),i)
+#define bhv_vop_frlock(vp,c,fl,flags,offset,fr)                                \
+               VOP(vop_frlock, vp)(VNHEAD(vp),c,fl,flags,offset,fr)
+#define bhv_vop_reclaim(vp)            VOP(vop_reclaim, vp)(VNHEAD(vp))
+#define bhv_vop_attr_get(vp, name, val, vallenp, fl, cred)             \
+               VOP(vop_attr_get, vp)(VNHEAD(vp),name,val,vallenp,fl,cred)
+#define        bhv_vop_attr_set(vp, name, val, vallen, fl, cred)               \
+               VOP(vop_attr_set, vp)(VNHEAD(vp),name,val,vallen,fl,cred)
+#define        bhv_vop_attr_remove(vp, name, flags, cred)                      \
+               VOP(vop_attr_remove, vp)(VNHEAD(vp),name,flags,cred)
+#define        bhv_vop_attr_list(vp, buf, buflen, fl, cursor, cred)            \
+               VOP(vop_attr_list, vp)(VNHEAD(vp),buf,buflen,fl,cursor,cred)
+#define bhv_vop_link_removed(vp, dvp, linkzero)                                \
+               VOP(vop_link_removed, vp)(VNHEAD(vp), dvp, linkzero)
+#define bhv_vop_vnode_change(vp, cmd, val)                             \
+               VOP(vop_vnode_change, vp)(VNHEAD(vp), cmd, val)
+#define bhv_vop_toss_pages(vp, first, last, fiopt)                     \
+               VOP(vop_tosspages, vp)(VNHEAD(vp), first, last, fiopt)
+#define bhv_vop_flushinval_pages(vp, first, last, fiopt)               \
+               VOP(vop_flushinval_pages, vp)(VNHEAD(vp),first,last,fiopt)
+#define bhv_vop_flush_pages(vp, first, last, flags, fiopt)             \
+               VOP(vop_flush_pages, vp)(VNHEAD(vp),first,last,flags,fiopt)
+#define bhv_vop_ioctl(vp, inode, filp, fl, cmd, arg)                   \
+               VOP(vop_ioctl, vp)(VNHEAD(vp),inode,filp,fl,cmd,arg)
+#define bhv_vop_iflush(vp, flags)      VOP(vop_iflush, vp)(VNHEAD(vp), flags)
 
 /*
  * Flags for read/write calls - same values as IRIX
@@ -377,7 +326,7 @@ typedef struct vnodeops {
 #define IO_INVIS       0x00020         /* don't update inode timestamps */
 
 /*
- * Flags for VOP_IFLUSH call
+ * Flags for vop_iflush call
  */
 #define FLUSH_SYNC             1       /* wait for flush to complete   */
 #define FLUSH_INODE            2       /* flush the inode itself       */
@@ -385,8 +334,7 @@ typedef struct vnodeops {
                                         * this inode out to disk       */
 
 /*
- * Flush/Invalidate options for VOP_TOSS_PAGES, VOP_FLUSHINVAL_PAGES and
- *     VOP_FLUSH_PAGES.
+ * Flush/Invalidate options for vop_toss/flush/flushinval_pages.
  */
 #define FI_NONE                        0       /* none */
 #define FI_REMAPF              1       /* Do a remapf prior to the operation */
@@ -398,7 +346,7 @@ typedef struct vnodeops {
  * Vnode attributes.  va_mask indicates those attributes the caller
  * wants to set or extract.
  */
-typedef struct vattr {
+typedef struct bhv_vattr {
        int             va_mask;        /* bit-mask of attributes present */
        mode_t          va_mode;        /* file access mode and type */
        xfs_nlink_t     va_nlink;       /* number of references to file */
@@ -418,7 +366,7 @@ typedef struct vattr {
        u_long          va_nextents;    /* number of extents in file */
        u_long          va_anextents;   /* number of attr extents in file */
        prid_t          va_projid;      /* project id */
-} vattr_t;
+} bhv_vattr_t;
 
 /*
  * setattr or getattr attributes
@@ -492,29 +440,17 @@ typedef struct vattr {
        (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID)
 
 extern void    vn_init(void);
-extern vnode_t *vn_initialize(struct inode *);
-
-/*
- * vnode_map structures _must_ match vn_epoch and vnode structure sizes.
- */
-typedef struct vnode_map {
-       vfs_t           *v_vfsp;
-       vnumber_t       v_number;               /* in-core vnode number */
-       xfs_ino_t       v_ino;                  /* inode #      */
-} vmap_t;
-
-#define VMAP(vp, vmap) {(vmap).v_vfsp   = (vp)->v_vfsp,        \
-                        (vmap).v_number = (vp)->v_number,      \
-                        (vmap).v_ino    = (vp)->v_inode.i_ino; }
+extern bhv_vnode_t     *vn_initialize(struct inode *);
+extern int     vn_revalidate(struct bhv_vnode *);
+extern int     __vn_revalidate(struct bhv_vnode *, bhv_vattr_t *);
+extern void    vn_revalidate_core(struct bhv_vnode *, bhv_vattr_t *);
 
-extern int     vn_revalidate(struct vnode *);
-extern int     __vn_revalidate(struct vnode *, vattr_t *);
-extern void    vn_revalidate_core(struct vnode *, vattr_t *);
+extern void    vn_iowait(struct bhv_vnode *vp);
+extern void    vn_iowake(struct bhv_vnode *vp);
 
-extern void    vn_iowait(struct vnode *vp);
-extern void    vn_iowake(struct vnode *vp);
+extern void    vn_ioerror(struct bhv_vnode *vp, int error, char *f, int l);
 
-static inline int vn_count(struct vnode *vp)
+static inline int vn_count(struct bhv_vnode *vp)
 {
        return atomic_read(&vn_to_inode(vp)->i_count);
 }
@@ -522,7 +458,7 @@ static inline int vn_count(struct vnode *vp)
 /*
  * Vnode reference counting functions (and macros for compatibility).
  */
-extern vnode_t *vn_hold(struct vnode *);
+extern bhv_vnode_t     *vn_hold(struct bhv_vnode *);
 
 #if defined(XFS_VNODE_TRACE)
 #define VN_HOLD(vp)            \
@@ -536,7 +472,7 @@ extern vnode_t      *vn_hold(struct vnode *);
 #define VN_RELE(vp)            (iput(vn_to_inode(vp)))
 #endif
 
-static inline struct vnode *vn_grab(struct vnode *vp)
+static inline struct bhv_vnode *vn_grab(struct bhv_vnode *vp)
 {
        struct inode *inode = igrab(vn_to_inode(vp));
        return inode ? vn_from_inode(inode) : NULL;
@@ -554,32 +490,39 @@ static inline struct vnode *vn_grab(struct vnode *vp)
  */
 #define VN_LOCK(vp)            mutex_spinlock(&(vp)->v_lock)
 #define VN_UNLOCK(vp, s)       mutex_spinunlock(&(vp)->v_lock, s)
-#define VN_FLAGSET(vp,b)       vn_flagset(vp,b)
-#define VN_FLAGCLR(vp,b)       vn_flagclr(vp,b)
 
-static __inline__ void vn_flagset(struct vnode *vp, uint flag)
+static __inline__ void vn_flagset(struct bhv_vnode *vp, uint flag)
 {
        spin_lock(&vp->v_lock);
        vp->v_flag |= flag;
        spin_unlock(&vp->v_lock);
 }
 
-static __inline__ void vn_flagclr(struct vnode *vp, uint flag)
+static __inline__ uint vn_flagclr(struct bhv_vnode *vp, uint flag)
 {
+       uint    cleared;
+
        spin_lock(&vp->v_lock);
+       cleared = (vp->v_flag & flag);
        vp->v_flag &= ~flag;
        spin_unlock(&vp->v_lock);
+       return cleared;
 }
 
+#define VMODIFY(vp)    vn_flagset(vp, VMODIFIED)
+#define VUNMODIFY(vp)  vn_flagclr(vp, VMODIFIED)
+#define VTRUNCATE(vp)  vn_flagset(vp, VTRUNCATED)
+#define VUNTRUNCATE(vp)        vn_flagclr(vp, VTRUNCATED)
+
 /*
  * Dealing with bad inodes
  */
-static inline void vn_mark_bad(struct vnode *vp)
+static inline void vn_mark_bad(struct bhv_vnode *vp)
 {
        make_bad_inode(vn_to_inode(vp));
 }
 
-static inline int VN_BAD(struct vnode *vp)
+static inline int VN_BAD(struct bhv_vnode *vp)
 {
        return is_bad_inode(vn_to_inode(vp));
 }
@@ -587,18 +530,18 @@ static inline int VN_BAD(struct vnode *vp)
 /*
  * Extracting atime values in various formats
  */
-static inline void vn_atime_to_bstime(struct vnode *vp, xfs_bstime_t *bs_atime)
+static inline void vn_atime_to_bstime(bhv_vnode_t *vp, xfs_bstime_t *bs_atime)
 {
        bs_atime->tv_sec = vp->v_inode.i_atime.tv_sec;
        bs_atime->tv_nsec = vp->v_inode.i_atime.tv_nsec;
 }
 
-static inline void vn_atime_to_timespec(struct vnode *vp, struct timespec *ts)
+static inline void vn_atime_to_timespec(bhv_vnode_t *vp, struct timespec *ts)
 {
        *ts = vp->v_inode.i_atime;
 }
 
-static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt)
+static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt)
 {
        *tt = vp->v_inode.i_atime.tv_sec;
 }
@@ -610,11 +553,10 @@ static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt)
 #define VN_CACHED(vp)  (vn_to_inode(vp)->i_mapping->nrpages)
 #define VN_DIRTY(vp)   mapping_tagged(vn_to_inode(vp)->i_mapping, \
                                        PAGECACHE_TAG_DIRTY)
-#define VMODIFY(vp)    VN_FLAGSET(vp, VMODIFIED)
-#define VUNMODIFY(vp)  VN_FLAGCLR(vp, VMODIFIED)
+#define VN_TRUNC(vp)   ((vp)->v_flag & VTRUNCATED)
 
 /*
- * Flags to VOP_SETATTR/VOP_GETATTR.
+ * Flags to vop_setattr/getattr.
  */
 #define        ATTR_UTIME      0x01    /* non-default utime(2) request */
 #define        ATTR_DMI        0x08    /* invocation from a DMI function */
@@ -624,7 +566,7 @@ static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt)
 #define ATTR_NOSIZETOK 0x400   /* Don't get the SIZE token */
 
 /*
- * Flags to VOP_FSYNC and VOP_RECLAIM.
+ * Flags to vop_fsync/reclaim.
  */
 #define FSYNC_NOWAIT   0       /* asynchronous flush */
 #define FSYNC_WAIT     0x1     /* synchronous fsync or forced reclaim */
@@ -643,11 +585,11 @@ static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt)
 #define        VNODE_KTRACE_REF        4
 #define        VNODE_KTRACE_RELE       5
 
-extern void vn_trace_entry(struct vnode *, const char *, inst_t *);
-extern void vn_trace_exit(struct vnode *, const char *, inst_t *);
-extern void vn_trace_hold(struct vnode *, char *, int, inst_t *);
-extern void vn_trace_ref(struct vnode *, char *, int, inst_t *);
-extern void vn_trace_rele(struct vnode *, char *, int, inst_t *);
+extern void vn_trace_entry(struct bhv_vnode *, const char *, inst_t *);
+extern void vn_trace_exit(struct bhv_vnode *, const char *, inst_t *);
+extern void vn_trace_hold(struct bhv_vnode *, char *, int, inst_t *);
+extern void vn_trace_ref(struct bhv_vnode *, char *, int, inst_t *);
+extern void vn_trace_rele(struct bhv_vnode *, char *, int, inst_t *);
 
 #define        VN_TRACE(vp)            \
        vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address)
index 772ac48329ea04661193044f68fc417507db214e..3aa771531856219a47f936013c1fcf046ef09eaa 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -444,7 +442,7 @@ xfs_qm_dqalloc(
                              XFS_BMAPI_METADATA | XFS_BMAPI_WRITE,
                              &firstblock,
                              XFS_QM_DQALLOC_SPACE_RES(mp),
-                             &map, &nmaps, &flist))) {
+                             &map, &nmaps, &flist, NULL))) {
                goto error0;
        }
        ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
@@ -559,7 +557,7 @@ xfs_qm_dqtobp(
                error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset,
                                  XFS_DQUOT_CLUSTER_SIZE_FSB,
                                  XFS_BMAPI_METADATA,
-                                 NULL, 0, &map, &nmaps, NULL);
+                                 NULL, 0, &map, &nmaps, NULL, NULL);
 
                xfs_iunlock(quotip, XFS_ILOCK_SHARED);
                if (error)
@@ -1261,7 +1259,7 @@ xfs_qm_dqflush(
 
        if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id),
                           0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) {
-               xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
+               xfs_force_shutdown(dqp->q_mount, SHUTDOWN_CORRUPT_INCORE);
                return XFS_ERROR(EIO);
        }
 
index c0c629663a5c7206e3d115b81f24684799a6513d..78d3ab95c5fda9224c9927e3cb6816aac907d7b8 100644 (file)
@@ -119,7 +119,7 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
  */
 #define xfs_dqflock(dqp)        { psema(&((dqp)->q_flock), PINOD | PRECALC);\
                                   (dqp)->dq_flags |= XFS_DQ_FLOCKED; }
-#define xfs_dqfunlock(dqp)      { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \
+#define xfs_dqfunlock(dqp)      { ASSERT(issemalocked(&((dqp)->q_flock))); \
                                   vsema(&((dqp)->q_flock)); \
                                   (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); }
 
@@ -128,7 +128,7 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp)
 #define XFS_DQ_PINUNLOCK(dqp, s)   mutex_spinunlock( \
                                     &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s)
 
-#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0)
+#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (issemalocked(&((dqp)->q_flock)))
 #define XFS_DQ_IS_ON_FREELIST(dqp)  ((dqp)->dq_flnext != (dqp))
 #define XFS_DQ_IS_DIRTY(dqp)   ((dqp)->dq_flags & XFS_DQ_DIRTY)
 #define XFS_QM_ISUDQ(dqp)      ((dqp)->dq_flags & XFS_DQ_USER)
index 546f48af882ae306cb2a5d52949db1e32bd1bf39..5b2dcc58b24430105bcca1860d7a589e811a3228 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -248,7 +246,7 @@ xfs_qm_dquot_logitem_pushbuf(
         * inode flush completed and the inode was taken off the AIL.
         * So, just get out.
         */
-       if ((valusema(&(dqp->q_flock)) > 0)  ||
+       if (!issemalocked(&(dqp->q_flock))  ||
            ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) {
                qip->qli_pushbuf_flag = 0;
                xfs_dqunlock(dqp);
@@ -261,7 +259,7 @@ xfs_qm_dquot_logitem_pushbuf(
        if (bp != NULL) {
                if (XFS_BUF_ISDELAYWRITE(bp)) {
                        dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) &&
-                                 (valusema(&(dqp->q_flock)) <= 0));
+                                 issemalocked(&(dqp->q_flock)));
                        qip->qli_pushbuf_flag = 0;
                        xfs_dqunlock(dqp);
 
index 7fb5eca9bd5017df4ba44267ef496c7319b260f7..e23e45535c48219855daa75be9aa60d2f977c790 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -33,7 +32,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -1603,7 +1601,7 @@ xfs_qm_dqiterate(
                                  maxlblkcnt - lblkno,
                                  XFS_BMAPI_METADATA,
                                  NULL,
-                                 0, map, &nmaps, NULL);
+                                 0, map, &nmaps, NULL, NULL);
                xfs_iunlock(qip, XFS_ILOCK_SHARED);
                if (error)
                        break;
@@ -1905,9 +1903,7 @@ xfs_qm_quotacheck(
                 */
                if ((error = xfs_bulkstat(mp, &lastino, &count,
                                     xfs_qm_dqusage_adjust, NULL,
-                                    structsz, NULL,
-                                    BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED,
-                                    &done)))
+                                    structsz, NULL, BULKSTAT_FG_IGET, &done)))
                        break;
 
        } while (! done);
index 6838b36d95a9bc283850aef2a12a1d680a8ea6f1..e95e99f7168fdb78f6f7b724fbc66a5acdf35aef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -33,7 +32,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -129,7 +127,7 @@ xfs_qm_parseargs(
                return XFS_ERROR(EINVAL);
        }
 
-       PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error);
+       error = bhv_next_vfs_parseargs(BHV_NEXT(bhv), options, args, update);
        if (!error && !referenced)
                bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM);
        return error;
@@ -140,9 +138,8 @@ xfs_qm_showargs(
        struct bhv_desc         *bhv,
        struct seq_file         *m)
 {
-       struct vfs              *vfsp = bhvtovfs(bhv);
+       struct bhv_vfs          *vfsp = bhvtovfs(bhv);
        struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
-       int                     error;
 
        if (mp->m_qflags & XFS_UQUOTA_ACCT) {
                (mp->m_qflags & XFS_UQUOTA_ENFD) ?
@@ -165,8 +162,7 @@ xfs_qm_showargs(
        if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT))
                seq_puts(m, "," MNTOPT_NOQUOTA);
 
-       PVFS_SHOWARGS(BHV_NEXT(bhv), m, error);
-       return error;
+       return bhv_next_vfs_showargs(BHV_NEXT(bhv), m);
 }
 
 STATIC int
@@ -175,14 +171,67 @@ xfs_qm_mount(
        struct xfs_mount_args   *args,
        struct cred             *cr)
 {
-       struct vfs              *vfsp = bhvtovfs(bhv);
+       struct bhv_vfs          *vfsp = bhvtovfs(bhv);
        struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
-       int                     error;
 
        if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA))
                xfs_qm_mount_quotainit(mp, args->flags);
-       PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error);
-       return error;
+       return bhv_next_vfs_mount(BHV_NEXT(bhv), args, cr);
+}
+
+/*
+ * Directory tree accounting is implemented using project quotas, where
+ * the project identifier is inherited from parent directories.
+ * A statvfs (df, etc.) of a directory that is using project quota should
+ * return a statvfs of the project, not the entire filesystem.
+ * This makes such trees appear as if they are filesystems in themselves.
+ */
+STATIC int
+xfs_qm_statvfs(
+       struct bhv_desc         *bhv,
+       bhv_statvfs_t           *statp,
+       struct bhv_vnode        *vnode)
+{
+       xfs_mount_t             *mp;
+       xfs_inode_t             *ip;
+       xfs_dquot_t             *dqp;
+       xfs_disk_dquot_t        *dp;
+       __uint64_t              limit;
+       int                     error;
+
+       error = bhv_next_vfs_statvfs(BHV_NEXT(bhv), statp, vnode);
+       if (error || !vnode)
+               return error;
+
+       mp = XFS_BHVTOM(bhv);
+       ip = xfs_vtoi(vnode);
+
+       if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT))
+               return 0;
+       if (!(mp->m_qflags & XFS_PQUOTA_ACCT))
+               return 0;
+       if (!(mp->m_qflags & XFS_OQUOTA_ENFD))
+               return 0;
+
+       if (xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp))
+               return 0;
+       dp = &dqp->q_core;
+
+       limit = dp->d_blk_softlimit ? dp->d_blk_softlimit : dp->d_blk_hardlimit;
+       if (limit && statp->f_blocks > limit) {
+               statp->f_blocks = limit;
+               statp->f_bfree = (statp->f_blocks > dp->d_bcount) ?
+                                       (statp->f_blocks - dp->d_bcount) : 0;
+       }
+       limit = dp->d_ino_softlimit ? dp->d_ino_softlimit : dp->d_ino_hardlimit;
+       if (limit && statp->f_files > limit) {
+               statp->f_files = limit;
+               statp->f_ffree = (statp->f_files > dp->d_icount) ?
+                                       (statp->f_ffree - dp->d_icount) : 0;
+       }
+
+       xfs_qm_dqput(dqp);
+       return 0;
 }
 
 STATIC int
@@ -191,7 +240,7 @@ xfs_qm_syncall(
        int                     flags,
        cred_t                  *credp)
 {
-       struct vfs              *vfsp = bhvtovfs(bhv);
+       struct bhv_vfs          *vfsp = bhvtovfs(bhv);
        struct xfs_mount        *mp = XFS_VFSTOM(vfsp);
        int                     error;
 
@@ -210,8 +259,7 @@ xfs_qm_syncall(
                        }
                }
        }
-       PVFS_SYNC(BHV_NEXT(bhv), flags, credp, error);
-       return error;
+       return bhv_next_vfs_sync(BHV_NEXT(bhv), flags, credp);
 }
 
 STATIC int
@@ -346,11 +394,12 @@ STATIC struct xfs_qmops xfs_qmcore_xfs = {
        .xfs_dqtrxops           = &xfs_trans_dquot_ops,
 };
 
-struct bhv_vfsops xfs_qmops = { {
+struct bhv_module_vfsops xfs_qmops = { {
        BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM),
        .vfs_parseargs          = xfs_qm_parseargs,
        .vfs_showargs           = xfs_qm_showargs,
        .vfs_mount              = xfs_qm_mount,
+       .vfs_statvfs            = xfs_qm_statvfs,
        .vfs_sync               = xfs_qm_syncall,
        .vfs_quotactl           = xfs_qm_quotactl, },
 };
index 0570f77335505b3ab52a2e46ea74b0ef17eaf049..6f858fb81a369edfdb99deee3f14e7d782806364 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
index c55db463bbf2b1b7895a461c1bb7cb18ae15f7bd..ed620c4d15941396e5bec0cc27cb0628a0b7dbc6 100644 (file)
@@ -26,7 +26,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -35,7 +34,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -91,8 +89,8 @@ xfs_qm_quotactl(
        xfs_caddr_t     addr)
 {
        xfs_mount_t     *mp;
+       bhv_vfs_t       *vfsp;
        int             error;
-       struct vfs      *vfsp;
 
        vfsp = bhvtovfs(bdp);
        mp = XFS_VFSTOM(vfsp);
@@ -1035,7 +1033,7 @@ xfs_qm_dqrele_all_inodes(
 {
        xfs_inode_t     *ip, *topino;
        uint            ireclaims;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
        boolean_t       vnode_refd;
 
        ASSERT(mp->m_quotainfo);
index 9168918db252fa3c55087f173c0c418da70f7b9e..0242e9666e8e087b3180938aefca3f198df28724 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -33,7 +32,6 @@
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_attr_sf.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
index b08b3d9345b7660972cb341fb876ac1ba77cb52c..36fbeccdc722c27a5492076fad587b13f98d5e8c 100644 (file)
@@ -47,7 +47,7 @@ cmn_err(register int level, char *fmt, ...)
        va_start(ap, fmt);
        if (*fmt == '!') fp++;
        len = vsprintf(message, fp, ap);
-       if (message[len-1] != '\n')
+       if (level != CE_DEBUG && message[len-1] != '\n')
                strcat(message, "\n");
        printk("%s%s", err_level[level], message);
        va_end(ap);
@@ -68,7 +68,7 @@ icmn_err(register int level, char *fmt, va_list ap)
                level = XFS_MAX_ERR_LEVEL;
        spin_lock_irqsave(&xfs_err_lock,flags);
        len = vsprintf(message, fmt, ap);
-       if (message[len-1] != '\n')
+       if (level != CE_DEBUG && message[len-1] != '\n')
                strcat(message, "\n");
        spin_unlock_irqrestore(&xfs_err_lock,flags);
        printk("%s%s", err_level[level], message);
index e3bf58112e7ec3492cbe4be9fd546b39a59cbbff..4f54dca662a89ca646f9ff27a51d129a1c42a4de 100644 (file)
@@ -33,9 +33,6 @@ extern void cmn_err(int, char *, ...)
        __attribute__ ((format (printf, 2, 3)));
 extern void assfail(char *expr, char *f, int l);
 
-#define prdev(fmt,targ,args...) \
-       printk("Device %s - " fmt "\n", XFS_BUFTARG_NAME(targ), ## args)
-
 #define ASSERT_ALWAYS(expr)    \
        (unlikely((expr) != 0) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
 
index 2539af34eb6376cd48c948f84398d1b9d843b443..4b0cb474be4c3906c79fa6e997f8b2e1e3c15639 100644 (file)
 #include "xfs_bit.h"
 #include "xfs_inum.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include <linux/capability.h>
 #include <linux/posix_acl_xattr.h>
 
-STATIC int     xfs_acl_setmode(vnode_t *, xfs_acl_t *, int *);
+STATIC int     xfs_acl_setmode(bhv_vnode_t *, xfs_acl_t *, int *);
 STATIC void     xfs_acl_filter_mode(mode_t, xfs_acl_t *);
 STATIC void    xfs_acl_get_endian(xfs_acl_t *);
 STATIC int     xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);
 STATIC int     xfs_acl_invalid(xfs_acl_t *);
 STATIC void    xfs_acl_sync_mode(mode_t, xfs_acl_t *);
-STATIC void    xfs_acl_get_attr(vnode_t *, xfs_acl_t *, int, int, int *);
-STATIC void    xfs_acl_set_attr(vnode_t *, xfs_acl_t *, int, int *);
-STATIC int     xfs_acl_allow_set(vnode_t *, int);
+STATIC void    xfs_acl_get_attr(bhv_vnode_t *, xfs_acl_t *, int, int, int *);
+STATIC void    xfs_acl_set_attr(bhv_vnode_t *, xfs_acl_t *, int, int *);
+STATIC int     xfs_acl_allow_set(bhv_vnode_t *, int);
 
 kmem_zone_t *xfs_acl_zone;
 
@@ -57,7 +55,7 @@ kmem_zone_t *xfs_acl_zone;
  */
 int
 xfs_acl_vhasacl_access(
-       vnode_t         *vp)
+       bhv_vnode_t     *vp)
 {
        int             error;
 
@@ -70,7 +68,7 @@ xfs_acl_vhasacl_access(
  */
 int
 xfs_acl_vhasacl_default(
-       vnode_t         *vp)
+       bhv_vnode_t     *vp)
 {
        int             error;
 
@@ -209,7 +207,7 @@ posix_acl_xfs_to_xattr(
 
 int
 xfs_acl_vget(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        void            *acl,
        size_t          size,
        int             kind)
@@ -241,10 +239,10 @@ xfs_acl_vget(
                        goto out;
                }
                if (kind == _ACL_TYPE_ACCESS) {
-                       vattr_t va;
+                       bhv_vattr_t     va;
 
                        va.va_mask = XFS_AT_MODE;
-                       VOP_GETATTR(vp, &va, 0, sys_cred, error);
+                       error = bhv_vop_getattr(vp, &va, 0, sys_cred);
                        if (error)
                                goto out;
                        xfs_acl_sync_mode(va.va_mode, xfs_acl);
@@ -260,7 +258,7 @@ out:
 
 int
 xfs_acl_vremove(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        int             kind)
 {
        int             error;
@@ -268,9 +266,9 @@ xfs_acl_vremove(
        VN_HOLD(vp);
        error = xfs_acl_allow_set(vp, kind);
        if (!error) {
-               VOP_ATTR_REMOVE(vp, kind == _ACL_TYPE_DEFAULT?
-                               SGI_ACL_DEFAULT: SGI_ACL_FILE,
-                               ATTR_ROOT, sys_cred, error);
+               error = bhv_vop_attr_remove(vp, kind == _ACL_TYPE_DEFAULT?
+                                               SGI_ACL_DEFAULT: SGI_ACL_FILE,
+                                               ATTR_ROOT, sys_cred);
                if (error == ENOATTR)
                        error = 0;      /* 'scool */
        }
@@ -280,7 +278,7 @@ xfs_acl_vremove(
 
 int
 xfs_acl_vset(
-       vnode_t                 *vp,
+       bhv_vnode_t             *vp,
        void                    *acl,
        size_t                  size,
        int                     kind)
@@ -370,10 +368,10 @@ xfs_acl_iaccess(
 
 STATIC int
 xfs_acl_allow_set(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        int             kind)
 {
-       vattr_t         va;
+       bhv_vattr_t     va;
        int             error;
 
        if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
@@ -383,7 +381,7 @@ xfs_acl_allow_set(
        if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
                return EROFS;
        va.va_mask = XFS_AT_UID;
-       VOP_GETATTR(vp, &va, 0, NULL, error);
+       error = bhv_vop_getattr(vp, &va, 0, NULL);
        if (error)
                return error;
        if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
@@ -606,7 +604,7 @@ xfs_acl_get_endian(
  */
 STATIC void
 xfs_acl_get_attr(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        xfs_acl_t       *aclp,
        int             kind,
        int             flags,
@@ -616,9 +614,9 @@ xfs_acl_get_attr(
 
        ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1);
        flags |= ATTR_ROOT;
-       VOP_ATTR_GET(vp,
-               kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT,
-               (char *)aclp, &len, flags, sys_cred, *error);
+       *error = bhv_vop_attr_get(vp, kind == _ACL_TYPE_ACCESS ?
+                                       SGI_ACL_FILE : SGI_ACL_DEFAULT,
+                                       (char *)aclp, &len, flags, sys_cred);
        if (*error || (flags & ATTR_KERNOVAL))
                return;
        xfs_acl_get_endian(aclp);
@@ -629,7 +627,7 @@ xfs_acl_get_attr(
  */
 STATIC void
 xfs_acl_set_attr(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        xfs_acl_t       *aclp,
        int             kind,
        int             *error)
@@ -654,19 +652,19 @@ xfs_acl_set_attr(
                INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm);
        }
        INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
-       VOP_ATTR_SET(vp,
-               kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT,
-               (char *)newacl, len, ATTR_ROOT, sys_cred, *error);
+       *error = bhv_vop_attr_set(vp, kind == _ACL_TYPE_ACCESS ?
+                               SGI_ACL_FILE: SGI_ACL_DEFAULT,
+                               (char *)newacl, len, ATTR_ROOT, sys_cred);
        _ACL_FREE(newacl);
 }
 
 int
 xfs_acl_vtoacl(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        xfs_acl_t       *access_acl,
        xfs_acl_t       *default_acl)
 {
-       vattr_t         va;
+       bhv_vattr_t     va;
        int             error = 0;
 
        if (access_acl) {
@@ -678,7 +676,7 @@ xfs_acl_vtoacl(
                if (!error) {
                        /* Got the ACL, need the mode... */
                        va.va_mask = XFS_AT_MODE;
-                       VOP_GETATTR(vp, &va, 0, sys_cred, error);
+                       error = bhv_vop_getattr(vp, &va, 0, sys_cred);
                }
 
                if (error)
@@ -701,8 +699,8 @@ xfs_acl_vtoacl(
  */
 int
 xfs_acl_inherit(
-       vnode_t         *vp,
-       vattr_t         *vap,
+       bhv_vnode_t     *vp,
+       bhv_vattr_t     *vap,
        xfs_acl_t       *pdaclp)
 {
        xfs_acl_t       *cacl;
@@ -757,11 +755,11 @@ xfs_acl_inherit(
  */
 STATIC int
 xfs_acl_setmode(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        xfs_acl_t       *acl,
        int             *basicperms)
 {
-       vattr_t         va;
+       bhv_vattr_t     va;
        xfs_acl_entry_t *ap;
        xfs_acl_entry_t *gap = NULL;
        int             i, error, nomask = 1;
@@ -776,7 +774,7 @@ xfs_acl_setmode(
         * mode.  The m:: bits take precedence over the g:: bits.
         */
        va.va_mask = XFS_AT_MODE;
-       VOP_GETATTR(vp, &va, 0, sys_cred, error);
+       error = bhv_vop_getattr(vp, &va, 0, sys_cred);
        if (error)
                return error;
 
@@ -810,8 +808,7 @@ xfs_acl_setmode(
        if (gap && nomask)
                va.va_mode |= gap->ae_perm << 3;
 
-       VOP_SETATTR(vp, &va, 0, sys_cred, error);
-       return error;
+       return bhv_vop_setattr(vp, &va, 0, sys_cred);
 }
 
 /*
index 538d0d65b04c720bf032ceee18a7ed485d517f6f..f853cf1a627058256fd88a43333e821d70c9ef19 100644 (file)
@@ -50,7 +50,7 @@ typedef struct xfs_acl {
 #ifdef CONFIG_XFS_POSIX_ACL
 
 struct vattr;
-struct vnode;
+struct bhv_vnode;
 struct xfs_inode;
 
 extern struct kmem_zone *xfs_acl_zone;
@@ -58,14 +58,14 @@ extern struct kmem_zone *xfs_acl_zone;
                (zone) = kmem_zone_init(sizeof(xfs_acl_t), (name))
 #define xfs_acl_zone_destroy(zone)     kmem_zone_destroy(zone)
 
-extern int xfs_acl_inherit(struct vnode *, struct vattr *, xfs_acl_t *);
+extern int xfs_acl_inherit(struct bhv_vnode *, struct bhv_vattr *, xfs_acl_t *);
 extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *);
-extern int xfs_acl_vtoacl(struct vnode *, xfs_acl_t *, xfs_acl_t *);
-extern int xfs_acl_vhasacl_access(struct vnode *);
-extern int xfs_acl_vhasacl_default(struct vnode *);
-extern int xfs_acl_vset(struct vnode *, void *, size_t, int);
-extern int xfs_acl_vget(struct vnode *, void *, size_t, int);
-extern int xfs_acl_vremove(struct vnode *vp, int);
+extern int xfs_acl_vtoacl(struct bhv_vnode *, xfs_acl_t *, xfs_acl_t *);
+extern int xfs_acl_vhasacl_access(struct bhv_vnode *);
+extern int xfs_acl_vhasacl_default(struct bhv_vnode *);
+extern int xfs_acl_vset(struct bhv_vnode *, void *, size_t, int);
+extern int xfs_acl_vget(struct bhv_vnode *, void *, size_t, int);
+extern int xfs_acl_vremove(struct bhv_vnode *, int);
 
 #define _ACL_TYPE_ACCESS       1
 #define _ACL_TYPE_DEFAULT      2
index 8558226281c45a61d7a0bc056505246e705a372b..eef6763f3a6732084ede458d4a8b38b5e01e3fd4 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -1862,7 +1860,7 @@ xfs_alloc_fix_freelist(
                (pag->pagf_longest - delta) :
                (pag->pagf_flcount > 0 || pag->pagf_longest > 0);
        if (args->minlen + args->alignment + args->minalignslop - 1 > longest ||
-           (args->minleft &&
+           (!(flags & XFS_ALLOC_FLAG_FREEING) &&
             (int)(pag->pagf_freeblks + pag->pagf_flcount -
                   need - args->total) <
             (int)args->minleft)) {
@@ -1898,7 +1896,7 @@ xfs_alloc_fix_freelist(
        longest = (longest > delta) ? (longest - delta) :
                (be32_to_cpu(agf->agf_flcount) > 0 || longest > 0);
        if (args->minlen + args->alignment + args->minalignslop - 1 > longest ||
-            (args->minleft &&
+            (!(flags & XFS_ALLOC_FLAG_FREEING) &&
                (int)(be32_to_cpu(agf->agf_freeblks) +
                   be32_to_cpu(agf->agf_flcount) - need - args->total) <
             (int)args->minleft)) {
@@ -1951,8 +1949,14 @@ xfs_alloc_fix_freelist(
                 * the restrictions correctly.  Can happen for free calls
                 * on a completely full ag.
                 */
-               if (targs.agbno == NULLAGBLOCK)
+               if (targs.agbno == NULLAGBLOCK) {
+                       if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
+                               xfs_trans_brelse(tp, agflbp);
+                               args->agbp = NULL;
+                               return 0;
+                       }
                        break;
+               }
                /*
                 * Put each allocated block on the list.
                 */
@@ -2360,8 +2364,19 @@ xfs_alloc_vextent(
                        if (args->agno == sagno &&
                            type == XFS_ALLOCTYPE_START_BNO)
                                args->type = XFS_ALLOCTYPE_THIS_AG;
-                       if (++(args->agno) == mp->m_sb.sb_agcount)
-                               args->agno = 0;
+                       /*
+                       * For the first allocation, we can try any AG to get
+                       * space.  However, if we already have allocated a
+                       * block, we don't want to try AGs whose number is below
+                       * sagno. Otherwise, we may end up with out-of-order
+                       * locking of AGF, which might cause deadlock.
+                       */
+                       if (++(args->agno) == mp->m_sb.sb_agcount) {
+                               if (args->firstblock != NULLFSBLOCK)
+                                       args->agno = sagno;
+                               else
+                                       args->agno = 0;
+                       }
                        /*
                         * Reached the starting a.g., must either be done
                         * or switch to non-trylock mode.
@@ -2443,7 +2458,7 @@ xfs_free_extent(
        args.minlen = args.minleft = args.minalignslop = 0;
        down_read(&args.mp->m_peraglock);
        args.pag = &args.mp->m_perag[args.agno];
-       if ((error = xfs_alloc_fix_freelist(&args, 0)))
+       if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING)))
                goto error0;
 #ifdef DEBUG
        ASSERT(args.agbp != NULL);
index 2d1f8928b2677dcb153cc8c9448ce41b3034fd83..650591f999ae4f1dd60eb575930246e7d3592758 100644 (file)
@@ -41,6 +41,7 @@ typedef enum xfs_alloctype
  * Flags for xfs_alloc_fix_freelist.
  */
 #define        XFS_ALLOC_FLAG_TRYLOCK  0x00000001  /* use trylock for buffer locking */
+#define        XFS_ALLOC_FLAG_FREEING  0x00000002  /* indicate caller is freeing extents*/
 
 /*
  * Argument structure for xfs_alloc routines.
@@ -70,6 +71,7 @@ typedef struct xfs_alloc_arg {
        char            wasfromfl;      /* set if allocation is from freelist */
        char            isfl;           /* set if is freelist blocks - !acctg */
        char            userdata;       /* set if this is user data */
+       xfs_fsblock_t   firstblock;     /* io first block allocated */
 } xfs_alloc_arg_t;
 
 /*
index a1d92da86ccd04e33c33e2dbb1752daea04c1430..7446556e8021092cecbba838bf9fa9214cf2ed01 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
index b6e1e02bbb285bd5bda5c090f4a85d6e6789494e..1a210104327547b77768e6fd6cd58f7618bac090 100644 (file)
@@ -27,7 +27,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -35,7 +34,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -1910,7 +1908,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
                error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
                                  args->rmtblkcnt,
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 NULL, 0, map, &nmap, NULL);
+                                 NULL, 0, map, &nmap, NULL, NULL);
                if (error)
                        return(error);
                ASSERT(nmap >= 1);
@@ -1988,7 +1986,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
                                                        XFS_BMAPI_WRITE,
                                  args->firstblock, args->total, &map, &nmap,
-                                 args->flist);
+                                 args->flist, NULL);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                *args->firstblock, &committed);
@@ -2039,7 +2037,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno,
                                  args->rmtblkcnt,
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 args->firstblock, 0, &map, &nmap, NULL);
+                                 args->firstblock, 0, &map, &nmap,
+                                 NULL, NULL);
                if (error) {
                        return(error);
                }
@@ -2104,7 +2103,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                                        args->rmtblkcnt,
                                        XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
                                        args->firstblock, 0, &map, &nmap,
-                                       args->flist);
+                                       args->flist, NULL);
                if (error) {
                        return(error);
                }
@@ -2142,7 +2141,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                XFS_BMAP_INIT(args->flist, args->firstblock);
                error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
                                    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                   1, args->firstblock, args->flist, &done);
+                                   1, args->firstblock, args->flist,
+                                   NULL, &done);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                *args->firstblock, &committed);
@@ -2322,56 +2322,56 @@ xfs_attr_trace_enter(int type, char *where,
 
 STATIC int
 posix_acl_access_set(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
 }
 
 STATIC int
 posix_acl_access_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
        return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
 }
 
 STATIC int
 posix_acl_access_get(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
 }
 
 STATIC int
 posix_acl_access_exists(
-       vnode_t *vp)
+       bhv_vnode_t *vp)
 {
        return xfs_acl_vhasacl_access(vp);
 }
 
 STATIC int
 posix_acl_default_set(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
 }
 
 STATIC int
 posix_acl_default_get(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
 }
 
 STATIC int
 posix_acl_default_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
        return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
 }
 
 STATIC int
 posix_acl_default_exists(
-       vnode_t *vp)
+       bhv_vnode_t *vp)
 {
        return xfs_acl_vhasacl_default(vp);
 }
@@ -2404,21 +2404,18 @@ STATIC struct attrnames *attr_system_names[] =
 
 STATIC int
 attr_generic_set(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
-       int     error;
-
-       VOP_ATTR_SET(vp, name, data, size, xflags, NULL, error);
-       return -error;
+       return -bhv_vop_attr_set(vp, name, data, size, xflags, NULL);
 }
 
 STATIC int
 attr_generic_get(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        int     error, asize = size;
 
-       VOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error);
+       error = bhv_vop_attr_get(vp, name, data, &asize, xflags, NULL);
        if (!error)
                return asize;
        return -error;
@@ -2426,12 +2423,9 @@ attr_generic_get(
 
 STATIC int
 attr_generic_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
-       int     error;
-
-       VOP_ATTR_REMOVE(vp, name, xflags, NULL, error);
-       return -error;
+       return -bhv_vop_attr_remove(vp, name, xflags, NULL);
 }
 
 STATIC int
@@ -2459,7 +2453,7 @@ attr_generic_listadd(
 
 STATIC int
 attr_system_list(
-       struct vnode            *vp,
+       bhv_vnode_t             *vp,
        void                    *data,
        size_t                  size,
        ssize_t                 *result)
@@ -2481,12 +2475,12 @@ attr_system_list(
 
 int
 attr_generic_list(
-       struct vnode *vp, void *data, size_t size, int xflags, ssize_t *result)
+       bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result)
 {
        attrlist_cursor_kern_t  cursor = { 0 };
        int                     error;
 
-       VOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error);
+       error = bhv_vop_attr_list(vp, data, size, xflags, &cursor, NULL);
        if (error > 0)
                return -error;
        *result = -error;
@@ -2514,7 +2508,7 @@ attr_lookup_namespace(
  */
 STATIC int
 attr_user_capable(
-       struct vnode    *vp,
+       bhv_vnode_t     *vp,
        cred_t          *cred)
 {
        struct inode    *inode = vn_to_inode(vp);
@@ -2532,7 +2526,7 @@ attr_user_capable(
 
 STATIC int
 attr_trusted_capable(
-       struct vnode    *vp,
+       bhv_vnode_t     *vp,
        cred_t          *cred)
 {
        struct inode    *inode = vn_to_inode(vp);
@@ -2546,7 +2540,7 @@ attr_trusted_capable(
 
 STATIC int
 attr_secure_capable(
-       struct vnode    *vp,
+       bhv_vnode_t     *vp,
        cred_t          *cred)
 {
        return -ENOSECURITY;
@@ -2554,7 +2548,7 @@ attr_secure_capable(
 
 STATIC int
 attr_system_set(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        attrnames_t     *namesp;
        int             error;
@@ -2573,7 +2567,7 @@ attr_system_set(
 
 STATIC int
 attr_system_get(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        attrnames_t     *namesp;
 
@@ -2585,7 +2579,7 @@ attr_system_get(
 
 STATIC int
 attr_system_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
        attrnames_t     *namesp;
 
index b2c7b9fcded3a4f6eed106027e61d07f3618de0e..981633f6c077cb96128bbe730b3deb7809f16bc4 100644 (file)
  *========================================================================*/
 
 struct cred;
-struct vnode;
+struct bhv_vnode;
 
-typedef int (*attrset_t)(struct vnode *, char *, void *, size_t, int);
-typedef int (*attrget_t)(struct vnode *, char *, void *, size_t, int);
-typedef int (*attrremove_t)(struct vnode *, char *, int);
-typedef int (*attrexists_t)(struct vnode *);
-typedef int (*attrcapable_t)(struct vnode *, struct cred *);
+typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int);
+typedef int (*attrget_t)(struct bhv_vnode *, char *, void *, size_t, int);
+typedef int (*attrremove_t)(struct bhv_vnode *, char *, int);
+typedef int (*attrexists_t)(struct bhv_vnode *);
+typedef int (*attrcapable_t)(struct bhv_vnode *, struct cred *);
 
 typedef struct attrnames {
        char *          attr_name;
@@ -63,7 +63,7 @@ extern struct attrnames attr_trusted;
 extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
 
 extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
-extern int attr_generic_list(struct vnode *, void *, size_t, int, ssize_t *);
+extern int attr_generic_list(struct bhv_vnode *, void *, size_t, int, ssize_t *);
 
 #define ATTR_DONTFOLLOW        0x0001  /* -- unused, from IRIX -- */
 #define ATTR_ROOT      0x0002  /* use attrs in root (trusted) namespace */
index 9462be86aa1477c495b971463106900117f2ba39..9455051f01208e61ae7d32cf9ab2cbad858d5fe7 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -34,7 +33,6 @@
 #include "xfs_ialloc_btree.h"
 #include "xfs_alloc.h"
 #include "xfs_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -2990,7 +2988,7 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
                nmap = 1;
                error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt,
                                        XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                       NULL, 0, &map, &nmap, NULL);
+                                       NULL, 0, &map, &nmap, NULL, NULL);
                if (error) {
                        return(error);
                }
index 26939d364bc47bbcff7d52bce28d06ac988939d1..3a61375390645f2bf6f2d5d54c5b4f988af97f0e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_mount.h"
 #include "xfs_ialloc.h"
 #include "xfs_itable.h"
+#include "xfs_dir2_data.h"
+#include "xfs_dir2_leaf.h"
+#include "xfs_dir2_block.h"
 #include "xfs_inode_item.h"
 #include "xfs_extfree_item.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
-#include "xfs_dir_leaf.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_rw.h"
 #include "xfs_quota.h"
@@ -101,6 +101,7 @@ xfs_bmap_add_extent(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd);  /* OK to allocate reserved blocks */
 
@@ -118,6 +119,7 @@ xfs_bmap_add_extent_delay_real(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd);  /* OK to allocate reserved blocks */
 
 /*
@@ -131,6 +133,7 @@ xfs_bmap_add_extent_hole_delay(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp,/* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd);  /* OK to allocate reserved blocks */
 
 /*
@@ -144,6 +147,7 @@ xfs_bmap_add_extent_hole_real(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork); /* data or attr fork */
 
 /*
@@ -156,7 +160,8 @@ xfs_bmap_add_extent_unwritten_real(
        xfs_extnum_t            idx,    /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp); /* inode logging flags */
+       int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta); /* Change made to incore extents */
 
 /*
  * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
@@ -203,6 +208,7 @@ xfs_bmap_del_extent(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp,/* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd);   /* OK to allocate reserved blocks */
 
@@ -510,7 +516,7 @@ xfs_bmap_add_attrfork_local(
                dargs.total = mp->m_dirblkfsbs;
                dargs.whichfork = XFS_DATA_FORK;
                dargs.trans = tp;
-               error = XFS_DIR_SHORTFORM_TO_SINGLE(mp, &dargs);
+               error = xfs_dir2_sf_to_block(&dargs);
        } else
                error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags,
                        XFS_DATA_FORK);
@@ -530,6 +536,7 @@ xfs_bmap_add_extent(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd)   /* OK to use reserved data blocks */
 {
@@ -567,6 +574,15 @@ xfs_bmap_add_extent(
                        logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
                } else
                        logflags = 0;
+               /* DELTA: single new extent */
+               if (delta) {
+                       if (delta->xed_startoff > new->br_startoff)
+                               delta->xed_startoff = new->br_startoff;
+                       if (delta->xed_blockcount <
+                                       new->br_startoff + new->br_blockcount)
+                               delta->xed_blockcount = new->br_startoff +
+                                               new->br_blockcount;
+               }
        }
        /*
         * Any kind of new delayed allocation goes here.
@@ -576,7 +592,7 @@ xfs_bmap_add_extent(
                        ASSERT((cur->bc_private.b.flags &
                                XFS_BTCUR_BPRV_WASDEL) == 0);
                if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new,
-                               &logflags, rsvd)))
+                               &logflags, delta, rsvd)))
                        goto done;
        }
        /*
@@ -587,7 +603,7 @@ xfs_bmap_add_extent(
                        ASSERT((cur->bc_private.b.flags &
                                XFS_BTCUR_BPRV_WASDEL) == 0);
                if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
-                               &logflags, whichfork)))
+                               &logflags, delta, whichfork)))
                        goto done;
        } else {
                xfs_bmbt_irec_t prev;   /* old extent at offset idx */
@@ -612,17 +628,17 @@ xfs_bmap_add_extent(
                                                XFS_BTCUR_BPRV_WASDEL);
                                if ((error = xfs_bmap_add_extent_delay_real(ip,
                                        idx, &cur, new, &da_new, first, flist,
-                                       &logflags, rsvd)))
+                                       &logflags, delta, rsvd)))
                                        goto done;
                        } else if (new->br_state == XFS_EXT_NORM) {
                                ASSERT(new->br_state == XFS_EXT_NORM);
                                if ((error = xfs_bmap_add_extent_unwritten_real(
-                                       ip, idx, &cur, new, &logflags)))
+                                       ip, idx, &cur, new, &logflags, delta)))
                                        goto done;
                        } else {
                                ASSERT(new->br_state == XFS_EXT_UNWRITTEN);
                                if ((error = xfs_bmap_add_extent_unwritten_real(
-                                       ip, idx, &cur, new, &logflags)))
+                                       ip, idx, &cur, new, &logflags, delta)))
                                        goto done;
                        }
                        ASSERT(*curp == cur || *curp == NULL);
@@ -635,7 +651,7 @@ xfs_bmap_add_extent(
                                ASSERT((cur->bc_private.b.flags &
                                        XFS_BTCUR_BPRV_WASDEL) == 0);
                        if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
-                                       new, &logflags, whichfork)))
+                                       new, &logflags, delta, whichfork)))
                                goto done;
                }
        }
@@ -700,6 +716,7 @@ xfs_bmap_add_extent_delay_real(
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
        xfs_bmap_free_t         *flist, /* list of extents to be freed */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd)   /* OK to use reserved data block allocation */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor */
@@ -716,8 +733,8 @@ xfs_bmap_add_extent_delay_real(
                                        /* left is 0, right is 1, prev is 2 */
        int                     rval=0; /* return value (logging flags) */
        int                     state = 0;/* state bits, accessed thru macros */
-       xfs_filblks_t           temp;   /* value for dnew calculations */
-       xfs_filblks_t           temp2;  /* value for dnew calculations */
+       xfs_filblks_t           temp=0; /* value for dnew calculations */
+       xfs_filblks_t           temp2=0;/* value for dnew calculations */
        int                     tmp_rval;       /* partial logging flags */
        enum {                          /* bit number definitions for state */
                LEFT_CONTIG,    RIGHT_CONTIG,
@@ -839,6 +856,11 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                }
                *dnew = 0;
+               /* DELTA: Three in-core extents are replaced by one. */
+               temp = LEFT.br_startoff;
+               temp2 = LEFT.br_blockcount +
+                       PREV.br_blockcount +
+                       RIGHT.br_blockcount;
                break;
 
        case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG):
@@ -872,6 +894,10 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                }
                *dnew = 0;
+               /* DELTA: Two in-core extents are replaced by one. */
+               temp = LEFT.br_startoff;
+               temp2 = LEFT.br_blockcount +
+                       PREV.br_blockcount;
                break;
 
        case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG):
@@ -906,6 +932,10 @@ xfs_bmap_add_extent_delay_real(
                                goto done;
                }
                *dnew = 0;
+               /* DELTA: Two in-core extents are replaced by one. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount +
+                       RIGHT.br_blockcount;
                break;
 
        case MASK2(LEFT_FILLING, RIGHT_FILLING):
@@ -936,6 +966,9 @@ xfs_bmap_add_extent_delay_real(
                        ASSERT(i == 1);
                }
                *dnew = 0;
+               /* DELTA: The in-core extent described by new changed type. */
+               temp = new->br_startoff;
+               temp2 = new->br_blockcount;
                break;
 
        case MASK2(LEFT_FILLING, LEFT_CONTIG):
@@ -978,6 +1011,10 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx,
                        XFS_DATA_FORK);
                *dnew = temp;
+               /* DELTA: The boundary between two in-core extents moved. */
+               temp = LEFT.br_startoff;
+               temp2 = LEFT.br_blockcount +
+                       PREV.br_blockcount;
                break;
 
        case MASK(LEFT_FILLING):
@@ -1025,6 +1062,9 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1,
                        XFS_DATA_FORK);
                *dnew = temp;
+               /* DELTA: One in-core extent is split in two. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount;
                break;
 
        case MASK2(RIGHT_FILLING, RIGHT_CONTIG):
@@ -1067,6 +1107,10 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx,
                        XFS_DATA_FORK);
                *dnew = temp;
+               /* DELTA: The boundary between two in-core extents moved. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount +
+                       RIGHT.br_blockcount;
                break;
 
        case MASK(RIGHT_FILLING):
@@ -1112,6 +1156,9 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
                xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK);
                *dnew = temp;
+               /* DELTA: One in-core extent is split in two. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount;
                break;
 
        case 0:
@@ -1194,6 +1241,9 @@ xfs_bmap_add_extent_delay_real(
                xfs_bmap_trace_post_update(fname, "0", ip, idx + 2,
                        XFS_DATA_FORK);
                *dnew = temp + temp2;
+               /* DELTA: One in-core extent is split in three. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount;
                break;
 
        case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
@@ -1209,6 +1259,13 @@ xfs_bmap_add_extent_delay_real(
                ASSERT(0);
        }
        *curp = cur;
+       if (delta) {
+               temp2 += temp;
+               if (delta->xed_startoff > temp)
+                       delta->xed_startoff = temp;
+               if (delta->xed_blockcount < temp2)
+                       delta->xed_blockcount = temp2;
+       }
 done:
        *logflagsp = rval;
        return error;
@@ -1235,7 +1292,8 @@ xfs_bmap_add_extent_unwritten_real(
        xfs_extnum_t            idx,    /* extent number to update/insert */
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
-       int                     *logflagsp) /* inode logging flags */
+       int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta) /* Change made to incore extents */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor */
        xfs_bmbt_rec_t          *ep;    /* extent entry for idx */
@@ -1252,6 +1310,8 @@ xfs_bmap_add_extent_unwritten_real(
                                        /* left is 0, right is 1, prev is 2 */
        int                     rval=0; /* return value (logging flags) */
        int                     state = 0;/* state bits, accessed thru macros */
+       xfs_filblks_t           temp=0;
+       xfs_filblks_t           temp2=0;
        enum {                          /* bit number definitions for state */
                LEFT_CONTIG,    RIGHT_CONTIG,
                LEFT_FILLING,   RIGHT_FILLING,
@@ -1380,6 +1440,11 @@ xfs_bmap_add_extent_unwritten_real(
                                RIGHT.br_blockcount, LEFT.br_state)))
                                goto done;
                }
+               /* DELTA: Three in-core extents are replaced by one. */
+               temp = LEFT.br_startoff;
+               temp2 = LEFT.br_blockcount +
+                       PREV.br_blockcount +
+                       RIGHT.br_blockcount;
                break;
 
        case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG):
@@ -1419,6 +1484,10 @@ xfs_bmap_add_extent_unwritten_real(
                                LEFT.br_state)))
                                goto done;
                }
+               /* DELTA: Two in-core extents are replaced by one. */
+               temp = LEFT.br_startoff;
+               temp2 = LEFT.br_blockcount +
+                       PREV.br_blockcount;
                break;
 
        case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG):
@@ -1459,6 +1528,10 @@ xfs_bmap_add_extent_unwritten_real(
                                newext)))
                                goto done;
                }
+               /* DELTA: Two in-core extents are replaced by one. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount +
+                       RIGHT.br_blockcount;
                break;
 
        case MASK2(LEFT_FILLING, RIGHT_FILLING):
@@ -1487,6 +1560,9 @@ xfs_bmap_add_extent_unwritten_real(
                                newext)))
                                goto done;
                }
+               /* DELTA: The in-core extent described by new changed type. */
+               temp = new->br_startoff;
+               temp2 = new->br_blockcount;
                break;
 
        case MASK2(LEFT_FILLING, LEFT_CONTIG):
@@ -1534,6 +1610,10 @@ xfs_bmap_add_extent_unwritten_real(
                                LEFT.br_state))
                                goto done;
                }
+               /* DELTA: The boundary between two in-core extents moved. */
+               temp = LEFT.br_startoff;
+               temp2 = LEFT.br_blockcount +
+                       PREV.br_blockcount;
                break;
 
        case MASK(LEFT_FILLING):
@@ -1574,6 +1654,9 @@ xfs_bmap_add_extent_unwritten_real(
                                goto done;
                        ASSERT(i == 1);
                }
+               /* DELTA: One in-core extent is split in two. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount;
                break;
 
        case MASK2(RIGHT_FILLING, RIGHT_CONTIG):
@@ -1617,6 +1700,10 @@ xfs_bmap_add_extent_unwritten_real(
                                newext)))
                                goto done;
                }
+               /* DELTA: The boundary between two in-core extents moved. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount +
+                       RIGHT.br_blockcount;
                break;
 
        case MASK(RIGHT_FILLING):
@@ -1657,6 +1744,9 @@ xfs_bmap_add_extent_unwritten_real(
                                goto done;
                        ASSERT(i == 1);
                }
+               /* DELTA: One in-core extent is split in two. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount;
                break;
 
        case 0:
@@ -1710,6 +1800,9 @@ xfs_bmap_add_extent_unwritten_real(
                                goto done;
                        ASSERT(i == 1);
                }
+               /* DELTA: One in-core extent is split in three. */
+               temp = PREV.br_startoff;
+               temp2 = PREV.br_blockcount;
                break;
 
        case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):
@@ -1725,6 +1818,13 @@ xfs_bmap_add_extent_unwritten_real(
                ASSERT(0);
        }
        *curp = cur;
+       if (delta) {
+               temp2 += temp;
+               if (delta->xed_startoff > temp)
+                       delta->xed_startoff = temp;
+               if (delta->xed_blockcount < temp2)
+                       delta->xed_blockcount = temp2;
+       }
 done:
        *logflagsp = rval;
        return error;
@@ -1753,6 +1853,7 @@ xfs_bmap_add_extent_hole_delay(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     rsvd)           /* OK to allocate reserved blocks */
 {
        xfs_bmbt_rec_t          *ep;    /* extent record for idx */
@@ -1765,7 +1866,8 @@ xfs_bmap_add_extent_hole_delay(
        xfs_filblks_t           oldlen=0;       /* old indirect size */
        xfs_bmbt_irec_t         right;  /* right neighbor extent entry */
        int                     state;  /* state bits, accessed thru macros */
-       xfs_filblks_t           temp;   /* temp for indirect calculations */
+       xfs_filblks_t           temp=0; /* temp for indirect calculations */
+       xfs_filblks_t           temp2=0;
        enum {                          /* bit number definitions for state */
                LEFT_CONTIG,    RIGHT_CONTIG,
                LEFT_DELAY,     RIGHT_DELAY,
@@ -1844,6 +1946,9 @@ xfs_bmap_add_extent_hole_delay(
                        XFS_DATA_FORK);
                xfs_iext_remove(ifp, idx, 1);
                ip->i_df.if_lastex = idx - 1;
+               /* DELTA: Two in-core extents were replaced by one. */
+               temp2 = temp;
+               temp = left.br_startoff;
                break;
 
        case MASK(LEFT_CONTIG):
@@ -1864,6 +1969,9 @@ xfs_bmap_add_extent_hole_delay(
                xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1,
                        XFS_DATA_FORK);
                ip->i_df.if_lastex = idx - 1;
+               /* DELTA: One in-core extent grew into a hole. */
+               temp2 = temp;
+               temp = left.br_startoff;
                break;
 
        case MASK(RIGHT_CONTIG):
@@ -1881,6 +1989,9 @@ xfs_bmap_add_extent_hole_delay(
                        NULLSTARTBLOCK((int)newlen), temp, right.br_state);
                xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK);
                ip->i_df.if_lastex = idx;
+               /* DELTA: One in-core extent grew into a hole. */
+               temp2 = temp;
+               temp = new->br_startoff;
                break;
 
        case 0:
@@ -1894,6 +2005,9 @@ xfs_bmap_add_extent_hole_delay(
                        XFS_DATA_FORK);
                xfs_iext_insert(ifp, idx, 1, new);
                ip->i_df.if_lastex = idx;
+               /* DELTA: A new in-core extent was added in a hole. */
+               temp2 = new->br_blockcount;
+               temp = new->br_startoff;
                break;
        }
        if (oldlen != newlen) {
@@ -1904,6 +2018,13 @@ xfs_bmap_add_extent_hole_delay(
                 * Nothing to do for disk quota accounting here.
                 */
        }
+       if (delta) {
+               temp2 += temp;
+               if (delta->xed_startoff > temp)
+                       delta->xed_startoff = temp;
+               if (delta->xed_blockcount < temp2)
+                       delta->xed_blockcount = temp2;
+       }
        *logflagsp = 0;
        return 0;
 #undef MASK
@@ -1925,6 +2046,7 @@ xfs_bmap_add_extent_hole_real(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork) /* data or attr fork */
 {
        xfs_bmbt_rec_t          *ep;    /* pointer to extent entry ins. point */
@@ -1936,7 +2058,10 @@ xfs_bmap_add_extent_hole_real(
        xfs_ifork_t             *ifp;   /* inode fork pointer */
        xfs_bmbt_irec_t         left;   /* left neighbor extent entry */
        xfs_bmbt_irec_t         right;  /* right neighbor extent entry */
+       int                     rval=0; /* return value (logging flags) */
        int                     state;  /* state bits, accessed thru macros */
+       xfs_filblks_t           temp=0;
+       xfs_filblks_t           temp2=0;
        enum {                          /* bit number definitions for state */
                LEFT_CONTIG,    RIGHT_CONTIG,
                LEFT_DELAY,     RIGHT_DELAY,
@@ -1993,6 +2118,7 @@ xfs_bmap_add_extent_hole_real(
                 left.br_blockcount + new->br_blockcount +
                     right.br_blockcount <= MAXEXTLEN));
 
+       error = 0;
        /*
         * Select which case we're in here, and implement it.
         */
@@ -2018,25 +2144,35 @@ xfs_bmap_add_extent_hole_real(
                XFS_IFORK_NEXT_SET(ip, whichfork,
                        XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
                if (cur == NULL) {
-                       *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
-                       return 0;
+                       rval = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
+               } else {
+                       rval = XFS_ILOG_CORE;
+                       if ((error = xfs_bmbt_lookup_eq(cur,
+                                       right.br_startoff,
+                                       right.br_startblock,
+                                       right.br_blockcount, &i)))
+                               goto done;
+                       ASSERT(i == 1);
+                       if ((error = xfs_bmbt_delete(cur, &i)))
+                               goto done;
+                       ASSERT(i == 1);
+                       if ((error = xfs_bmbt_decrement(cur, 0, &i)))
+                               goto done;
+                       ASSERT(i == 1);
+                       if ((error = xfs_bmbt_update(cur, left.br_startoff,
+                                       left.br_startblock,
+                                       left.br_blockcount +
+                                               new->br_blockcount +
+                                               right.br_blockcount,
+                                       left.br_state)))
+                               goto done;
                }
-               *logflagsp = XFS_ILOG_CORE;
-               if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff,
-                               right.br_startblock, right.br_blockcount, &i)))
-                       return error;
-               ASSERT(i == 1);
-               if ((error = xfs_bmbt_delete(cur, &i)))
-                       return error;
-               ASSERT(i == 1);
-               if ((error = xfs_bmbt_decrement(cur, 0, &i)))
-                       return error;
-               ASSERT(i == 1);
-               error = xfs_bmbt_update(cur, left.br_startoff,
-                               left.br_startblock,
-                               left.br_blockcount + new->br_blockcount +
-                               right.br_blockcount, left.br_state);
-               return error;
+               /* DELTA: Two in-core extents were replaced by one. */
+               temp = left.br_startoff;
+               temp2 = left.br_blockcount +
+                       new->br_blockcount +
+                       right.br_blockcount;
+               break;
 
        case MASK(LEFT_CONTIG):
                /*
@@ -2050,19 +2186,27 @@ xfs_bmap_add_extent_hole_real(
                xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork);
                ifp->if_lastex = idx - 1;
                if (cur == NULL) {
-                       *logflagsp = XFS_ILOG_FEXT(whichfork);
-                       return 0;
+                       rval = XFS_ILOG_FEXT(whichfork);
+               } else {
+                       rval = 0;
+                       if ((error = xfs_bmbt_lookup_eq(cur,
+                                       left.br_startoff,
+                                       left.br_startblock,
+                                       left.br_blockcount, &i)))
+                               goto done;
+                       ASSERT(i == 1);
+                       if ((error = xfs_bmbt_update(cur, left.br_startoff,
+                                       left.br_startblock,
+                                       left.br_blockcount +
+                                               new->br_blockcount,
+                                       left.br_state)))
+                               goto done;
                }
-               *logflagsp = 0;
-               if ((error = xfs_bmbt_lookup_eq(cur, left.br_startoff,
-                               left.br_startblock, left.br_blockcount, &i)))
-                       return error;
-               ASSERT(i == 1);
-               error = xfs_bmbt_update(cur, left.br_startoff,
-                               left.br_startblock,
-                               left.br_blockcount + new->br_blockcount,
-                               left.br_state);
-               return error;
+               /* DELTA: One in-core extent grew. */
+               temp = left.br_startoff;
+               temp2 = left.br_blockcount +
+                       new->br_blockcount;
+               break;
 
        case MASK(RIGHT_CONTIG):
                /*
@@ -2077,19 +2221,27 @@ xfs_bmap_add_extent_hole_real(
                xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork);
                ifp->if_lastex = idx;
                if (cur == NULL) {
-                       *logflagsp = XFS_ILOG_FEXT(whichfork);
-                       return 0;
+                       rval = XFS_ILOG_FEXT(whichfork);
+               } else {
+                       rval = 0;
+                       if ((error = xfs_bmbt_lookup_eq(cur,
+                                       right.br_startoff,
+                                       right.br_startblock,
+                                       right.br_blockcount, &i)))
+                               goto done;
+                       ASSERT(i == 1);
+                       if ((error = xfs_bmbt_update(cur, new->br_startoff,
+                                       new->br_startblock,
+                                       new->br_blockcount +
+                                               right.br_blockcount,
+                                       right.br_state)))
+                               goto done;
                }
-               *logflagsp = 0;
-               if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff,
-                               right.br_startblock, right.br_blockcount, &i)))
-                       return error;
-               ASSERT(i == 1);
-               error = xfs_bmbt_update(cur, new->br_startoff,
-                               new->br_startblock,
-                               new->br_blockcount + right.br_blockcount,
-                               right.br_state);
-               return error;
+               /* DELTA: One in-core extent grew. */
+               temp = new->br_startoff;
+               temp2 = new->br_blockcount +
+                       right.br_blockcount;
+               break;
 
        case 0:
                /*
@@ -2104,29 +2256,41 @@ xfs_bmap_add_extent_hole_real(
                XFS_IFORK_NEXT_SET(ip, whichfork,
                        XFS_IFORK_NEXTENTS(ip, whichfork) + 1);
                if (cur == NULL) {
-                       *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
-                       return 0;
+                       rval = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);
+               } else {
+                       rval = XFS_ILOG_CORE;
+                       if ((error = xfs_bmbt_lookup_eq(cur,
+                                       new->br_startoff,
+                                       new->br_startblock,
+                                       new->br_blockcount, &i)))
+                               goto done;
+                       ASSERT(i == 0);
+                       cur->bc_rec.b.br_state = new->br_state;
+                       if ((error = xfs_bmbt_insert(cur, &i)))
+                               goto done;
+                       ASSERT(i == 1);
                }
-               *logflagsp = XFS_ILOG_CORE;
-               if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff,
-                               new->br_startblock, new->br_blockcount, &i)))
-                       return error;
-               ASSERT(i == 0);
-               cur->bc_rec.b.br_state = new->br_state;
-               if ((error = xfs_bmbt_insert(cur, &i)))
-                       return error;
-               ASSERT(i == 1);
-               return 0;
+               /* DELTA: A new extent was added in a hole. */
+               temp = new->br_startoff;
+               temp2 = new->br_blockcount;
+               break;
+       }
+       if (delta) {
+               temp2 += temp;
+               if (delta->xed_startoff > temp)
+                       delta->xed_startoff = temp;
+               if (delta->xed_blockcount < temp2)
+                       delta->xed_blockcount = temp2;
        }
+done:
+       *logflagsp = rval;
+       return error;
 #undef MASK
 #undef MASK2
 #undef STATE_SET
 #undef STATE_TEST
 #undef STATE_SET_TEST
 #undef SWITCH_STATE
-       /* NOTREACHED */
-       ASSERT(0);
-       return 0; /* keep gcc quite */
 }
 
 /*
@@ -2598,6 +2762,7 @@ xfs_bmap_btalloc(
        args.mp = mp;
        args.fsbno = ap->rval;
        args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks);
+       args.firstblock = ap->firstblock;
        blen = 0;
        if (nullfb) {
                args.type = XFS_ALLOCTYPE_START_BNO;
@@ -2657,7 +2822,7 @@ xfs_bmap_btalloc(
                else
                        args.minlen = ap->alen;
        } else if (ap->low) {
-               args.type = XFS_ALLOCTYPE_FIRST_AG;
+               args.type = XFS_ALLOCTYPE_START_BNO;
                args.total = args.minlen = ap->minlen;
        } else {
                args.type = XFS_ALLOCTYPE_NEAR_BNO;
@@ -2669,7 +2834,7 @@ xfs_bmap_btalloc(
                args.prod = ap->ip->i_d.di_extsize;
                if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod)))
                        args.mod = (xfs_extlen_t)(args.prod - args.mod);
-       } else if (unlikely(mp->m_sb.sb_blocksize >= NBPP)) {
+       } else if (mp->m_sb.sb_blocksize >= NBPP) {
                args.prod = 1;
                args.mod = 0;
        } else {
@@ -2885,6 +3050,7 @@ xfs_bmap_del_extent(
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *del,   /* data to remove from extents */
        int                     *logflagsp, /* inode logging flags */
+       xfs_extdelta_t          *delta, /* Change made to incore extents */
        int                     whichfork, /* data or attr fork */
        int                     rsvd)   /* OK to allocate reserved blocks */
 {
@@ -3193,6 +3359,14 @@ xfs_bmap_del_extent(
        if (da_old > da_new)
                xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new),
                        rsvd);
+       if (delta) {
+               /* DELTA: report the original extent. */
+               if (delta->xed_startoff > got.br_startoff)
+                       delta->xed_startoff = got.br_startoff;
+               if (delta->xed_blockcount < got.br_startoff+got.br_blockcount)
+                       delta->xed_blockcount = got.br_startoff +
+                                                       got.br_blockcount;
+       }
 done:
        *logflagsp = flags;
        return error;
@@ -3279,6 +3453,7 @@ xfs_bmap_extents_to_btree(
        XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE);
        args.tp = tp;
        args.mp = mp;
+       args.firstblock = *firstblock;
        if (*firstblock == NULLFSBLOCK) {
                args.type = XFS_ALLOCTYPE_START_BNO;
                args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino);
@@ -3414,6 +3589,7 @@ xfs_bmap_local_to_extents(
 
                args.tp = tp;
                args.mp = ip->i_mount;
+               args.firstblock = *firstblock;
                ASSERT((ifp->if_flags &
                        (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE);
                /*
@@ -3753,7 +3929,7 @@ xfs_bunmap_trace(
        if (ip->i_rwtrace == NULL)
                return;
        ktrace_enter(ip->i_rwtrace,
-               (void *)(__psint_t)XFS_BUNMAPI,
+               (void *)(__psint_t)XFS_BUNMAP,
                (void *)ip,
                (void *)(__psint_t)((ip->i_d.di_size >> 32) & 0xffffffff),
                (void *)(__psint_t)(ip->i_d.di_size & 0xffffffff),
@@ -4087,8 +4263,8 @@ xfs_bmap_finish(
                        if (!XFS_FORCED_SHUTDOWN(mp))
                                xfs_force_shutdown(mp,
                                                   (error == EFSCORRUPTED) ?
-                                                  XFS_CORRUPT_INCORE :
-                                                  XFS_METADATA_IO_ERROR);
+                                                  SHUTDOWN_CORRUPT_INCORE :
+                                                  SHUTDOWN_META_IO_ERROR);
                        return error;
                }
                xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock,
@@ -4538,7 +4714,8 @@ xfs_bmapi(
        xfs_extlen_t    total,          /* total blocks needed */
        xfs_bmbt_irec_t *mval,          /* output: map values */
        int             *nmap,          /* i/o: mval size/count */
-       xfs_bmap_free_t *flist)         /* i/o: list extents to free */
+       xfs_bmap_free_t *flist,         /* i/o: list extents to free */
+       xfs_extdelta_t  *delta)         /* o: change made to incore extents */
 {
        xfs_fsblock_t   abno;           /* allocated block number */
        xfs_extlen_t    alen;           /* allocated extent length */
@@ -4650,6 +4827,10 @@ xfs_bmapi(
        end = bno + len;
        obno = bno;
        bma.ip = NULL;
+       if (delta) {
+               delta->xed_startoff = NULLFILEOFF;
+               delta->xed_blockcount = 0;
+       }
        while (bno < end && n < *nmap) {
                /*
                 * Reading past eof, act as though there's a hole
@@ -4886,8 +5067,8 @@ xfs_bmapi(
                                        got.br_state = XFS_EXT_UNWRITTEN;
                        }
                        error = xfs_bmap_add_extent(ip, lastx, &cur, &got,
-                               firstblock, flist, &tmp_logflags, whichfork,
-                               (flags & XFS_BMAPI_RSVBLOCKS));
+                               firstblock, flist, &tmp_logflags, delta,
+                               whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
                        logflags |= tmp_logflags;
                        if (error)
                                goto error0;
@@ -4983,8 +5164,8 @@ xfs_bmapi(
                        }
                        mval->br_state = XFS_EXT_NORM;
                        error = xfs_bmap_add_extent(ip, lastx, &cur, mval,
-                               firstblock, flist, &tmp_logflags, whichfork,
-                               (flags & XFS_BMAPI_RSVBLOCKS));
+                               firstblock, flist, &tmp_logflags, delta,
+                               whichfork, (flags & XFS_BMAPI_RSVBLOCKS));
                        logflags |= tmp_logflags;
                        if (error)
                                goto error0;
@@ -5073,7 +5254,14 @@ xfs_bmapi(
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE ||
               XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max);
        error = 0;
-
+       if (delta && delta->xed_startoff != NULLFILEOFF) {
+               /* A change was actually made.
+                * Note that delta->xed_blockount is an offset at this
+                * point and needs to be converted to a block count.
+                */
+               ASSERT(delta->xed_blockcount > delta->xed_startoff);
+               delta->xed_blockcount -= delta->xed_startoff;
+       }
 error0:
        /*
         * Log everything.  Do this after conversion, there's no point in
@@ -5185,6 +5373,8 @@ xfs_bunmapi(
        xfs_fsblock_t           *firstblock,    /* first allocated block
                                                   controls a.g. for allocs */
        xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
+       xfs_extdelta_t          *delta,         /* o: change made to incore
+                                                  extents */
        int                     *done)          /* set if not done yet */
 {
        xfs_btree_cur_t         *cur;           /* bmap btree cursor */
@@ -5242,6 +5432,10 @@ xfs_bunmapi(
        bno = start + len - 1;
        ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got,
                &prev);
+       if (delta) {
+               delta->xed_startoff = NULLFILEOFF;
+               delta->xed_blockcount = 0;
+       }
        /*
         * Check to see if the given block number is past the end of the
         * file, back up to the last block if so...
@@ -5340,7 +5534,8 @@ xfs_bunmapi(
                        }
                        del.br_state = XFS_EXT_UNWRITTEN;
                        error = xfs_bmap_add_extent(ip, lastx, &cur, &del,
-                               firstblock, flist, &logflags, XFS_DATA_FORK, 0);
+                               firstblock, flist, &logflags, delta,
+                               XFS_DATA_FORK, 0);
                        if (error)
                                goto error0;
                        goto nodelete;
@@ -5394,7 +5589,7 @@ xfs_bunmapi(
                                prev.br_state = XFS_EXT_UNWRITTEN;
                                error = xfs_bmap_add_extent(ip, lastx - 1, &cur,
                                        &prev, firstblock, flist, &logflags,
-                                       XFS_DATA_FORK, 0);
+                                       delta, XFS_DATA_FORK, 0);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5403,7 +5598,7 @@ xfs_bunmapi(
                                del.br_state = XFS_EXT_UNWRITTEN;
                                error = xfs_bmap_add_extent(ip, lastx, &cur,
                                        &del, firstblock, flist, &logflags,
-                                       XFS_DATA_FORK, 0);
+                                       delta, XFS_DATA_FORK, 0);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5456,7 +5651,7 @@ xfs_bunmapi(
                        goto error0;
                }
                error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del,
-                       &tmp_logflags, whichfork, rsvd);
+                               &tmp_logflags, delta, whichfork, rsvd);
                logflags |= tmp_logflags;
                if (error)
                        goto error0;
@@ -5513,6 +5708,14 @@ nodelete:
        ASSERT(ifp->if_ext_max ==
               XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t));
        error = 0;
+       if (delta && delta->xed_startoff != NULLFILEOFF) {
+               /* A change was actually made.
+                * Note that delta->xed_blockount is an offset at this
+                * point and needs to be converted to a block count.
+                */
+               ASSERT(delta->xed_blockcount > delta->xed_startoff);
+               delta->xed_blockcount -= delta->xed_startoff;
+       }
 error0:
        /*
         * Log everything.  Do this after conversion, there's no point in
@@ -5556,7 +5759,7 @@ xfs_getbmap(
        __int64_t               fixlen;         /* length for -1 case */
        int                     i;              /* extent number */
        xfs_inode_t             *ip;            /* xfs incore inode pointer */
-       vnode_t                 *vp;            /* corresponding vnode */
+       bhv_vnode_t             *vp;            /* corresponding vnode */
        int                     lock;           /* lock state */
        xfs_bmbt_irec_t         *map;           /* buffer for user's data */
        xfs_mount_t             *mp;            /* file system mount point */
@@ -5653,7 +5856,7 @@ xfs_getbmap(
 
        if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) {
                /* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */
-               VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error);
+               error = bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF);
        }
 
        ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0);
@@ -5689,7 +5892,8 @@ xfs_getbmap(
                nmap = (nexleft > subnex) ? subnex : nexleft;
                error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
                                  XFS_BB_TO_FSB(mp, bmv->bmv_length),
-                                 bmapi_flags, NULL, 0, map, &nmap, NULL);
+                                 bmapi_flags, NULL, 0, map, &nmap,
+                                 NULL, NULL);
                if (error)
                        goto unlock_and_return;
                ASSERT(nmap <= subnex);
index 8e0d73d9ccc453557bc494cfe0158c60993cc43e..80e93409b78dbfb7122b246487cb27e60df7b7eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -25,6 +25,20 @@ struct xfs_inode;
 struct xfs_mount;
 struct xfs_trans;
 
+/*
+ * DELTA: describe a change to the in-core extent list.
+ *
+ * Internally the use of xed_blockount is somewhat funky.
+ * xed_blockcount contains an offset much of the time because this
+ * makes merging changes easier.  (xfs_fileoff_t and xfs_filblks_t are
+ * the same underlying type).
+ */
+typedef struct xfs_extdelta
+{
+       xfs_fileoff_t           xed_startoff;   /* offset of range */
+       xfs_filblks_t           xed_blockcount; /* blocks in range */
+} xfs_extdelta_t;
+
 /*
  * List of extents to be free "later".
  * The list is kept sorted on xbf_startblock.
@@ -275,7 +289,9 @@ xfs_bmapi(
        xfs_extlen_t            total,          /* total blocks needed */
        struct xfs_bmbt_irec    *mval,          /* output: map values */
        int                     *nmap,          /* i/o: mval size/count */
-       xfs_bmap_free_t         *flist);        /* i/o: list extents to free */
+       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
+       xfs_extdelta_t          *delta);        /* o: change made to incore
+                                                  extents */
 
 /*
  * Map file blocks to filesystem blocks, simple version.
@@ -309,6 +325,8 @@ xfs_bunmapi(
        xfs_fsblock_t           *firstblock,    /* first allocated block
                                                   controls a.g. for allocs */
        xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
+       xfs_extdelta_t          *delta,         /* o: change made to incore
+                                                  extents */
        int                     *done);         /* set if not done yet */
 
 /*
index bea44709afbecd8819842ef9c5cc3361a044981e..18fb7385d719fe4ad25b5f64ff23ec55d710d060 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -1569,12 +1567,11 @@ xfs_bmbt_split(
        lbno = XFS_DADDR_TO_FSB(args.mp, XFS_BUF_ADDR(lbp));
        left = XFS_BUF_TO_BMBT_BLOCK(lbp);
        args.fsbno = cur->bc_private.b.firstblock;
+       args.firstblock = args.fsbno;
        if (args.fsbno == NULLFSBLOCK) {
                args.fsbno = lbno;
                args.type = XFS_ALLOCTYPE_START_BNO;
-       } else if (cur->bc_private.b.flist->xbf_low)
-               args.type = XFS_ALLOCTYPE_FIRST_AG;
-       else
+       } else
                args.type = XFS_ALLOCTYPE_NEAR_BNO;
        args.mod = args.minleft = args.alignment = args.total = args.isfl =
                args.userdata = args.minalignslop = 0;
@@ -2356,6 +2353,7 @@ xfs_bmbt_newroot(
                args.userdata = args.minalignslop = 0;
        args.minlen = args.maxlen = args.prod = 1;
        args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL;
+       args.firstblock = args.fsbno;
        if (args.fsbno == NULLFSBLOCK) {
 #ifdef DEBUG
                if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) {
@@ -2365,9 +2363,7 @@ xfs_bmbt_newroot(
 #endif
                args.fsbno = INT_GET(*pp, ARCH_CONVERT);
                args.type = XFS_ALLOCTYPE_START_BNO;
-       } else if (args.wasdel)
-               args.type = XFS_ALLOCTYPE_FIRST_AG;
-       else
+       } else
                args.type = XFS_ALLOCTYPE_NEAR_BNO;
        if ((error = xfs_alloc_vextent(&args))) {
                XFS_BMBT_TRACE_CURSOR(cur, ERROR);
index 52d5d095fc3533dcd23100def7ab2f33d8fda2b8..ee2255bd65624051d63729ceddf4670b4ed9002f 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
index 5fed15682dda588d9e2c3e54ef9557de15123154..a4aa53974f7650668204ea2ce22f93de28adfa9c 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_buf_item.h"
@@ -1030,9 +1029,9 @@ xfs_buf_iodone_callbacks(
                if ((XFS_BUF_TARGET(bp) != lasttarg) ||
                    (time_after(jiffies, (lasttime + 5*HZ)))) {
                        lasttime = jiffies;
-                       prdev("XFS write error in file system meta-data "
-                             "block 0x%llx in %s",
-                             XFS_BUF_TARGET(bp),
+                       cmn_err(CE_ALERT, "Device %s, XFS metadata write error"
+                                       " block 0x%llx in %s",
+                               XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
                              (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname);
                }
                lasttarg = XFS_BUF_TARGET(bp);
@@ -1108,7 +1107,7 @@ xfs_buf_error_relse(
        XFS_BUF_ERROR(bp,0);
        xfs_buftrace("BUF_ERROR_RELSE", bp);
        if (! XFS_FORCED_SHUTDOWN(mp))
-               xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
        /*
         * We have to unpin the pinned buffers so do the
         * callbacks.
index d0035c6e951441362c364994523bf7b7e5b70a79..7a0e482dd4362a419592c0de70797dc49f01eeec 100644 (file)
@@ -49,12 +49,12 @@ typedef struct xfs_cap_set {
 
 #include <linux/posix_cap_xattr.h>
 
-struct vnode;
+struct bhv_vnode;
 
-extern int xfs_cap_vhascap(struct vnode *);
-extern int xfs_cap_vset(struct vnode *, void *, size_t);
-extern int xfs_cap_vget(struct vnode *, void *, size_t);
-extern int xfs_cap_vremove(struct vnode *vp);
+extern int xfs_cap_vhascap(struct bhv_vnode *);
+extern int xfs_cap_vset(struct bhv_vnode *, void *, size_t);
+extern int xfs_cap_vget(struct bhv_vnode *, void *, size_t);
+extern int xfs_cap_vremove(struct bhv_vnode *);
 
 #define _CAP_EXISTS            xfs_cap_vhascap
 
index 8988b9051175f98e14bb96eaa0d49630a5e473fe..32ab61d17acefdeab2683925b65b806e556f7d5d 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -43,7 +41,6 @@
 #include "xfs_bmap.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
-#include "xfs_dir_leaf.h"
 #include "xfs_dir2_data.h"
 #include "xfs_dir2_leaf.h"
 #include "xfs_dir2_block.h"
@@ -159,7 +156,7 @@ xfs_da_split(xfs_da_state_t *state)
        max = state->path.active - 1;
        ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH));
        ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC ||
-              state->path.blk[max].magic == XFS_DIRX_LEAF_MAGIC(state->mp));
+              state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC);
 
        addblk = &state->path.blk[max];         /* initial dummy value */
        for (i = max; (i >= 0) && addblk; state->path.active--, i--) {
@@ -199,38 +196,7 @@ xfs_da_split(xfs_da_state_t *state)
                                return(error);  /* GROT: attr inconsistent */
                        addblk = newblk;
                        break;
-               case XFS_DIR_LEAF_MAGIC:
-                       ASSERT(XFS_DIR_IS_V1(state->mp));
-                       error = xfs_dir_leaf_split(state, oldblk, newblk);
-                       if ((error != 0) && (error != ENOSPC)) {
-                               return(error);  /* GROT: dir is inconsistent */
-                       }
-                       if (!error) {
-                               addblk = newblk;
-                               break;
-                       }
-                       /*
-                        * Entry wouldn't fit, split the leaf again.
-                        */
-                       state->extravalid = 1;
-                       if (state->inleaf) {
-                               state->extraafter = 0;  /* before newblk */
-                               error = xfs_dir_leaf_split(state, oldblk,
-                                                          &state->extrablk);
-                               if (error)
-                                       return(error);  /* GROT: dir incon. */
-                               addblk = newblk;
-                       } else {
-                               state->extraafter = 1;  /* after newblk */
-                               error = xfs_dir_leaf_split(state, newblk,
-                                                          &state->extrablk);
-                               if (error)
-                                       return(error);  /* GROT: dir incon. */
-                               addblk = newblk;
-                       }
-                       break;
                case XFS_DIR2_LEAFN_MAGIC:
-                       ASSERT(XFS_DIR_IS_V2(state->mp));
                        error = xfs_dir2_leafn_split(state, oldblk, newblk);
                        if (error)
                                return error;
@@ -363,7 +329,6 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
                size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] -
                             (char *)oldroot);
        } else {
-               ASSERT(XFS_DIR_IS_V2(mp));
                ASSERT(be16_to_cpu(oldroot->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
                leaf = (xfs_dir2_leaf_t *)oldroot;
                size = (int)((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] -
@@ -379,8 +344,7 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
         * Set up the new root node.
         */
        error = xfs_da_node_create(args,
-               args->whichfork == XFS_DATA_FORK &&
-               XFS_DIR_IS_V2(mp) ? mp->m_dirleafblk : 0,
+               (args->whichfork == XFS_DATA_FORK) ? mp->m_dirleafblk : 0,
                be16_to_cpu(node->hdr.level) + 1, &bp, args->whichfork);
        if (error)
                return(error);
@@ -427,10 +391,9 @@ xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
        ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
 
        /*
-        * With V2 the extra block is data or freespace.
+        * With V2 dirs the extra block is data or freespace.
         */
-       useextra = state->extravalid && (XFS_DIR_IS_V1(state->mp) ||
-                       state->args->whichfork == XFS_ATTR_FORK);
+       useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK;
        newcount = 1 + useextra;
        /*
         * Do we have to split the node?
@@ -624,7 +587,7 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
        ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
        ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
        ASSERT(newblk->blkno != 0);
-       if (state->args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
+       if (state->args->whichfork == XFS_DATA_FORK)
                ASSERT(newblk->blkno >= mp->m_dirleafblk &&
                       newblk->blkno < mp->m_dirfreeblk);
 
@@ -670,7 +633,7 @@ xfs_da_join(xfs_da_state_t *state)
        save_blk = &state->altpath.blk[ state->path.active-1 ];
        ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC);
        ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC ||
-              drop_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp));
+              drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);
 
        /*
         * Walk back up the tree joining/deallocating as necessary.
@@ -693,17 +656,7 @@ xfs_da_join(xfs_da_state_t *state)
                                return(0);
                        xfs_attr_leaf_unbalance(state, drop_blk, save_blk);
                        break;
-               case XFS_DIR_LEAF_MAGIC:
-                       ASSERT(XFS_DIR_IS_V1(state->mp));
-                       error = xfs_dir_leaf_toosmall(state, &action);
-                       if (error)
-                               return(error);
-                       if (action == 0)
-                               return(0);
-                       xfs_dir_leaf_unbalance(state, drop_blk, save_blk);
-                       break;
                case XFS_DIR2_LEAFN_MAGIC:
-                       ASSERT(XFS_DIR_IS_V2(state->mp));
                        error = xfs_dir2_leafn_toosmall(state, &action);
                        if (error)
                                return error;
@@ -790,7 +743,7 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
        ASSERT(bp != NULL);
        blkinfo = bp->data;
        if (be16_to_cpu(oldroot->hdr.level) == 1) {
-               ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+               ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DIR2_LEAFN_MAGIC ||
                       be16_to_cpu(blkinfo->magic) == XFS_ATTR_LEAF_MAGIC);
        } else {
                ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DA_NODE_MAGIC);
@@ -951,14 +904,7 @@ xfs_da_fixhashpath(xfs_da_state_t *state, xfs_da_state_path_t *path)
                if (count == 0)
                        return;
                break;
-       case XFS_DIR_LEAF_MAGIC:
-               ASSERT(XFS_DIR_IS_V1(state->mp));
-               lasthash = xfs_dir_leaf_lasthash(blk->bp, &count);
-               if (count == 0)
-                       return;
-               break;
        case XFS_DIR2_LEAFN_MAGIC:
-               ASSERT(XFS_DIR_IS_V2(state->mp));
                lasthash = xfs_dir2_leafn_lasthash(blk->bp, &count);
                if (count == 0)
                        return;
@@ -1117,10 +1063,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
         * Descend thru the B-tree searching each level for the right
         * node to use, until the right hashval is found.
         */
-       if (args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(state->mp))
-               blkno = state->mp->m_dirleafblk;
-       else
-               blkno = 0;
+       blkno = (args->whichfork == XFS_DATA_FORK)? state->mp->m_dirleafblk : 0;
        for (blk = &state->path.blk[0], state->path.active = 1;
                         state->path.active <= XFS_DA_NODE_MAXDEPTH;
                         blk++, state->path.active++) {
@@ -1137,7 +1080,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
                }
                curr = blk->bp->data;
                ASSERT(be16_to_cpu(curr->magic) == XFS_DA_NODE_MAGIC ||
-                      be16_to_cpu(curr->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+                      be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC ||
                       be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC);
 
                /*
@@ -1190,16 +1133,10 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
                                blk->index = probe;
                                blkno = be32_to_cpu(btree->before);
                        }
-               }
-               else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) {
+               } else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) {
                        blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
                        break;
-               }
-               else if (be16_to_cpu(curr->magic) == XFS_DIR_LEAF_MAGIC) {
-                       blk->hashval = xfs_dir_leaf_lasthash(blk->bp, NULL);
-                       break;
-               }
-               else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) {
+               } else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) {
                        blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL);
                        break;
                }
@@ -1212,12 +1149,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
         * next leaf and keep searching.
         */
        for (;;) {
-               if (blk->magic == XFS_DIR_LEAF_MAGIC) {
-                       ASSERT(XFS_DIR_IS_V1(state->mp));
-                       retval = xfs_dir_leaf_lookup_int(blk->bp, args,
-                                                                 &blk->index);
-               } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
-                       ASSERT(XFS_DIR_IS_V2(state->mp));
+               if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
                        retval = xfs_dir2_leafn_lookup_int(blk->bp, args,
                                                        &blk->index, state);
                }
@@ -1270,7 +1202,7 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
        old_info = old_blk->bp->data;
        new_info = new_blk->bp->data;
        ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC ||
-              old_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+              old_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
               old_blk->magic == XFS_ATTR_LEAF_MAGIC);
        ASSERT(old_blk->magic == be16_to_cpu(old_info->magic));
        ASSERT(new_blk->magic == be16_to_cpu(new_info->magic));
@@ -1280,12 +1212,7 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
        case XFS_ATTR_LEAF_MAGIC:
                before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp);
                break;
-       case XFS_DIR_LEAF_MAGIC:
-               ASSERT(XFS_DIR_IS_V1(state->mp));
-               before = xfs_dir_leaf_order(old_blk->bp, new_blk->bp);
-               break;
        case XFS_DIR2_LEAFN_MAGIC:
-               ASSERT(XFS_DIR_IS_V2(state->mp));
                before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp);
                break;
        case XFS_DA_NODE_MAGIC:
@@ -1404,7 +1331,7 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
        save_info = save_blk->bp->data;
        drop_info = drop_blk->bp->data;
        ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC ||
-              save_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+              save_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
               save_blk->magic == XFS_ATTR_LEAF_MAGIC);
        ASSERT(save_blk->magic == be16_to_cpu(save_info->magic));
        ASSERT(drop_blk->magic == be16_to_cpu(drop_info->magic));
@@ -1529,7 +1456,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
                ASSERT(blk->bp != NULL);
                info = blk->bp->data;
                ASSERT(be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC ||
-                      be16_to_cpu(info->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
+                      be16_to_cpu(info->magic) == XFS_DIR2_LEAFN_MAGIC ||
                       be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC);
                blk->magic = be16_to_cpu(info->magic);
                if (blk->magic == XFS_DA_NODE_MAGIC) {
@@ -1548,20 +1475,13 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
                                blk->hashval = xfs_attr_leaf_lasthash(blk->bp,
                                                                      NULL);
                                break;
-                       case XFS_DIR_LEAF_MAGIC:
-                               ASSERT(XFS_DIR_IS_V1(state->mp));
-                               blk->hashval = xfs_dir_leaf_lasthash(blk->bp,
-                                                                    NULL);
-                               break;
                        case XFS_DIR2_LEAFN_MAGIC:
-                               ASSERT(XFS_DIR_IS_V2(state->mp));
                                blk->hashval = xfs_dir2_leafn_lasthash(blk->bp,
                                                                       NULL);
                                break;
                        default:
                                ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC ||
-                                      blk->magic ==
-                                      XFS_DIRX_LEAF_MAGIC(state->mp));
+                                      blk->magic == XFS_DIR2_LEAFN_MAGIC);
                                break;
                        }
                }
@@ -1620,7 +1540,6 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
        xfs_bmbt_irec_t *mapp;
        xfs_inode_t *dp;
        int nmap, error, w, count, c, got, i, mapi;
-       xfs_fsize_t size;
        xfs_trans_t *tp;
        xfs_mount_t *mp;
 
@@ -1631,7 +1550,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
        /*
         * For new directories adjust the file offset and block count.
         */
-       if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) {
+       if (w == XFS_DATA_FORK) {
                bno = mp->m_dirleafblk;
                count = mp->m_dirblkfsbs;
        } else {
@@ -1641,10 +1560,9 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
        /*
         * Find a spot in the file space to put the new block.
         */
-       if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w))) {
+       if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w)))
                return error;
-       }
-       if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
+       if (w == XFS_DATA_FORK)
                ASSERT(bno >= mp->m_dirleafblk && bno < mp->m_dirfreeblk);
        /*
         * Try mapping it in one filesystem block.
@@ -1655,7 +1573,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
                        XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|
                        XFS_BMAPI_CONTIG,
                        args->firstblock, args->total, &map, &nmap,
-                       args->flist))) {
+                       args->flist, NULL))) {
                return error;
        }
        ASSERT(nmap <= 1);
@@ -1676,7 +1594,8 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
                                        XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|
                                        XFS_BMAPI_METADATA,
                                        args->firstblock, args->total,
-                                       &mapp[mapi], &nmap, args->flist))) {
+                                       &mapp[mapi], &nmap, args->flist,
+                                       NULL))) {
                                kmem_free(mapp, sizeof(*mapp) * count);
                                return error;
                        }
@@ -1705,19 +1624,6 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno)
        if (mapp != &map)
                kmem_free(mapp, sizeof(*mapp) * count);
        *new_blkno = (xfs_dablk_t)bno;
-       /*
-        * For version 1 directories, adjust the file size if it changed.
-        */
-       if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) {
-               ASSERT(mapi == 1);
-               if ((error = xfs_bmap_last_offset(tp, dp, &bno, w)))
-                       return error;
-               size = XFS_FSB_TO_B(mp, bno);
-               if (size != dp->i_d.di_size) {
-                       dp->i_d.di_size = size;
-                       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
-               }
-       }
        return 0;
 }
 
@@ -1742,7 +1648,6 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        int error, w, entno, level, dead_level;
        xfs_da_blkinfo_t *dead_info, *sib_info;
        xfs_da_intnode_t *par_node, *dead_node;
-       xfs_dir_leafblock_t *dead_leaf;
        xfs_dir2_leaf_t *dead_leaf2;
        xfs_dahash_t dead_hash;
 
@@ -1753,11 +1658,8 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        w = args->whichfork;
        ASSERT(w == XFS_DATA_FORK);
        mp = ip->i_mount;
-       if (XFS_DIR_IS_V2(mp)) {
-               lastoff = mp->m_dirfreeblk;
-               error = xfs_bmap_last_before(tp, ip, &lastoff, w);
-       } else
-               error = xfs_bmap_last_offset(tp, ip, &lastoff, w);
+       lastoff = mp->m_dirfreeblk;
+       error = xfs_bmap_last_before(tp, ip, &lastoff, w);
        if (error)
                return error;
        if (unlikely(lastoff == 0)) {
@@ -1780,14 +1682,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        /*
         * Get values from the moved block.
         */
-       if (be16_to_cpu(dead_info->magic) == XFS_DIR_LEAF_MAGIC) {
-               ASSERT(XFS_DIR_IS_V1(mp));
-               dead_leaf = (xfs_dir_leafblock_t *)dead_info;
-               dead_level = 0;
-               dead_hash =
-                       INT_GET(dead_leaf->entries[INT_GET(dead_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
-       } else if (be16_to_cpu(dead_info->magic) == XFS_DIR2_LEAFN_MAGIC) {
-               ASSERT(XFS_DIR_IS_V2(mp));
+       if (be16_to_cpu(dead_info->magic) == XFS_DIR2_LEAFN_MAGIC) {
                dead_leaf2 = (xfs_dir2_leaf_t *)dead_info;
                dead_level = 0;
                dead_hash = be32_to_cpu(dead_leaf2->ents[be16_to_cpu(dead_leaf2->hdr.count) - 1].hashval);
@@ -1842,7 +1737,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
                xfs_da_buf_done(sib_buf);
                sib_buf = NULL;
        }
-       par_blkno = XFS_DIR_IS_V1(mp) ? 0 : mp->m_dirleafblk;
+       par_blkno = mp->m_dirleafblk;
        level = -1;
        /*
         * Walk down the tree looking for the parent of the moved block.
@@ -1941,8 +1836,6 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
 {
        xfs_inode_t *dp;
        int done, error, w, count;
-       xfs_fileoff_t bno;
-       xfs_fsize_t size;
        xfs_trans_t *tp;
        xfs_mount_t *mp;
 
@@ -1950,7 +1843,7 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
        w = args->whichfork;
        tp = args->trans;
        mp = dp->i_mount;
-       if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
+       if (w == XFS_DATA_FORK)
                count = mp->m_dirblkfsbs;
        else
                count = 1;
@@ -1961,34 +1854,17 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
                 */
                if ((error = xfs_bunmapi(tp, dp, dead_blkno, count,
                                XFS_BMAPI_AFLAG(w)|XFS_BMAPI_METADATA,
-                               0, args->firstblock, args->flist,
+                               0, args->firstblock, args->flist, NULL,
                                &done)) == ENOSPC) {
                        if (w != XFS_DATA_FORK)
-                               goto done;
+                               break;
                        if ((error = xfs_da_swap_lastblock(args, &dead_blkno,
                                        &dead_buf)))
-                               goto done;
-               } else if (error)
-                       goto done;
-               else
+                               break;
+               } else {
                        break;
-       }
-       ASSERT(done);
-       xfs_da_binval(tp, dead_buf);
-       /*
-        * Adjust the directory size for version 1.
-        */
-       if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) {
-               if ((error = xfs_bmap_last_offset(tp, dp, &bno, w)))
-                       return error;
-               size = XFS_FSB_TO_B(dp->i_mount, bno);
-               if (size != dp->i_d.di_size) {
-                       dp->i_d.di_size = size;
-                       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
                }
        }
-       return 0;
-done:
        xfs_da_binval(tp, dead_buf);
        return error;
 }
@@ -2049,10 +1925,7 @@ xfs_da_do_buf(
        xfs_dabuf_t     *rbp;
 
        mp = dp->i_mount;
-       if (whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
-               nfsb = mp->m_dirblkfsbs;
-       else
-               nfsb = 1;
+       nfsb = (whichfork == XFS_DATA_FORK) ? mp->m_dirblkfsbs : 1;
        mappedbno = *mappedbnop;
        /*
         * Caller doesn't have a mapping.  -2 means don't complain
@@ -2086,7 +1959,7 @@ xfs_da_do_buf(
                                        nfsb,
                                        XFS_BMAPI_METADATA |
                                                XFS_BMAPI_AFLAG(whichfork),
-                                       NULL, 0, mapp, &nmap, NULL)))
+                                       NULL, 0, mapp, &nmap, NULL, NULL)))
                                goto exit0;
                }
        } else {
@@ -2198,7 +2071,6 @@ xfs_da_do_buf(
                magic1 = be32_to_cpu(data->hdr.magic);
                if (unlikely(
                    XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) &&
-                                  (magic != XFS_DIR_LEAF_MAGIC) &&
                                   (magic != XFS_ATTR_LEAF_MAGIC) &&
                                   (magic != XFS_DIR2_LEAF1_MAGIC) &&
                                   (magic != XFS_DIR2_LEAFN_MAGIC) &&
index 243a730d5ec894e68db961fb826a4fb2d6689e23..4ab865ec8b82e18ef91f048c1605f85f405c4899 100644 (file)
@@ -36,14 +36,10 @@ struct zone;
  * level in the Btree, and to identify which type of block this is.
  */
 #define XFS_DA_NODE_MAGIC      0xfebe  /* magic number: non-leaf blocks */
-#define XFS_DIR_LEAF_MAGIC     0xfeeb  /* magic number: directory leaf blks */
 #define XFS_ATTR_LEAF_MAGIC    0xfbee  /* magic number: attribute leaf blks */
 #define        XFS_DIR2_LEAF1_MAGIC    0xd2f1  /* magic number: v2 dirlf single blks */
 #define        XFS_DIR2_LEAFN_MAGIC    0xd2ff  /* magic number: v2 dirlf multi blks */
 
-#define        XFS_DIRX_LEAF_MAGIC(mp) \
-       (XFS_DIR_IS_V1(mp) ? XFS_DIR_LEAF_MAGIC : XFS_DIR2_LEAFN_MAGIC)
-
 typedef struct xfs_da_blkinfo {
        __be32          forw;                   /* previous block in list */
        __be32          back;                   /* following block in list */
index 4968a6358e613acb627cc4e4e57aad45342a2367..80562b60fb95f5c041ee202701f011d1bb9a648c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -54,24 +52,14 @@ xfs_swapext(
        xfs_swapext_t   __user *sxu)
 {
        xfs_swapext_t   *sxp;
-       xfs_inode_t     *ip=NULL, *tip=NULL, *ips[2];
-       xfs_trans_t     *tp;
+       xfs_inode_t     *ip=NULL, *tip=NULL;
        xfs_mount_t     *mp;
-       xfs_bstat_t     *sbp;
        struct file     *fp = NULL, *tfp = NULL;
-       vnode_t         *vp, *tvp;
-       static uint     lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL;
-       int             ilf_fields, tilf_fields;
+       bhv_vnode_t     *vp, *tvp;
        int             error = 0;
-       xfs_ifork_t     *tempifp, *ifp, *tifp;
-       __uint64_t      tmp;
-       int             aforkblks = 0;
-       int             taforkblks = 0;
-       char            locked = 0;
 
        sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL);
-       tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
-       if (!sxp || !tempifp) {
+       if (!sxp) {
                error = XFS_ERROR(ENOMEM);
                goto error0;
        }
@@ -118,14 +106,56 @@ xfs_swapext(
 
        mp = ip->i_mount;
 
-       sbp = &sxp->sx_stat;
-
        if (XFS_FORCED_SHUTDOWN(mp)) {
                error =  XFS_ERROR(EIO);
                goto error0;
        }
 
-       locked = 1;
+       error = XFS_SWAP_EXTENTS(mp, &ip->i_iocore, &tip->i_iocore, sxp);
+
+ error0:
+       if (fp != NULL)
+               fput(fp);
+       if (tfp != NULL)
+               fput(tfp);
+
+       if (sxp != NULL)
+               kmem_free(sxp, sizeof(xfs_swapext_t));
+
+       return error;
+}
+
+int
+xfs_swap_extents(
+       xfs_inode_t     *ip,
+       xfs_inode_t     *tip,
+       xfs_swapext_t   *sxp)
+{
+       xfs_mount_t     *mp;
+       xfs_inode_t     *ips[2];
+       xfs_trans_t     *tp;
+       xfs_bstat_t     *sbp = &sxp->sx_stat;
+       bhv_vnode_t     *vp, *tvp;
+       xfs_ifork_t     *tempifp, *ifp, *tifp;
+       int             ilf_fields, tilf_fields;
+       static uint     lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL;
+       int             error = 0;
+       int             aforkblks = 0;
+       int             taforkblks = 0;
+       __uint64_t      tmp;
+       char            locked = 0;
+
+       mp = ip->i_mount;
+
+       tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
+       if (!tempifp) {
+               error = XFS_ERROR(ENOMEM);
+               goto error0;
+       }
+
+       sbp = &sxp->sx_stat;
+       vp = XFS_ITOV(ip);
+       tvp = XFS_ITOV(tip);
 
        /* Lock in i_ino order */
        if (ip->i_ino < tip->i_ino) {
@@ -137,6 +167,7 @@ xfs_swapext(
        }
 
        xfs_lock_inodes(ips, 2, 0, lock_flags);
+       locked = 1;
 
        /* Check permissions */
        error = xfs_iaccess(ip, S_IWUSR, NULL);
@@ -169,7 +200,7 @@ xfs_swapext(
 
        if (VN_CACHED(tvp) != 0) {
                xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1);
-               VOP_FLUSHINVAL_PAGES(tvp, 0, -1, FI_REMAPF_LOCKED);
+               bhv_vop_flushinval_pages(tvp, 0, -1, FI_REMAPF_LOCKED);
        }
 
        /* Verify O_DIRECT for ftmp */
@@ -214,7 +245,7 @@ xfs_swapext(
        /* We need to fail if the file is memory mapped.  Once we have tossed
         * all existing pages, the page fault will have no option
         * but to go to the filesystem for pages. By making the page fault call
-        * VOP_READ (or write in the case of autogrow) they block on the iolock
+        * vop_read (or write in the case of autogrow) they block on the iolock
         * until we have switched the extents.
         */
        if (VN_MAPPED(vp)) {
@@ -233,7 +264,7 @@ xfs_swapext(
         * fields change.
         */
 
-       VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF);
+       bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
        if ((error = xfs_trans_reserve(tp, 0,
@@ -360,16 +391,7 @@ xfs_swapext(
                xfs_iunlock(ip,  lock_flags);
                xfs_iunlock(tip, lock_flags);
        }
-
-       if (fp != NULL)
-               fput(fp);
-       if (tfp != NULL)
-               fput(tfp);
-
-       if (sxp != NULL)
-               kmem_free(sxp, sizeof(xfs_swapext_t));
        if (tempifp != NULL)
                kmem_free(tempifp, sizeof(xfs_ifork_t));
-
        return error;
 }
index f678559abc45ce1240af76a18ccc0765542fd69c..da178205be689210ba520b9ec8c80d5bd584e04f 100644 (file)
@@ -48,6 +48,9 @@ typedef struct xfs_swapext
  */
 int    xfs_swapext(struct xfs_swapext __user *sx);
 
+int    xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
+               struct xfs_swapext *sxp);
+
 #endif /* __KERNEL__ */
 
 #endif /* __XFS_DFRAG_H__ */
index 79d0d9e1fbabc8d4f38061c1191dd978fc447791..b33826961c458f794bdbe0f711014fb73bbac432 100644 (file)
@@ -85,7 +85,6 @@ typedef struct xfs_dinode
        union {
                xfs_bmdr_block_t di_bmbt;       /* btree root block */
                xfs_bmbt_rec_32_t di_bmx[1];    /* extent list */
-               xfs_dir_shortform_t di_dirsf;   /* shortform directory */
                xfs_dir2_sf_t   di_dir2sf;      /* shortform directory v2 */
                char            di_c[1];        /* local contents */
                xfs_dev_t       di_dev;         /* device for S_IFCHR/S_IFBLK */
@@ -257,6 +256,7 @@ typedef enum xfs_dinode_fmt
 #define XFS_DIFLAG_NOSYMLINKS_BIT   10 /* disallow symlink creation */
 #define XFS_DIFLAG_EXTSIZE_BIT      11 /* inode extent size allocator hint */
 #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */
+#define XFS_DIFLAG_NODEFRAG_BIT     13 /* do not reorganize/defragment */
 #define XFS_DIFLAG_REALTIME      (1 << XFS_DIFLAG_REALTIME_BIT)
 #define XFS_DIFLAG_PREALLOC      (1 << XFS_DIFLAG_PREALLOC_BIT)
 #define XFS_DIFLAG_NEWRTBM       (1 << XFS_DIFLAG_NEWRTBM_BIT)
@@ -270,12 +270,13 @@ typedef enum xfs_dinode_fmt
 #define XFS_DIFLAG_NOSYMLINKS    (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
 #define XFS_DIFLAG_EXTSIZE       (1 << XFS_DIFLAG_EXTSIZE_BIT)
 #define XFS_DIFLAG_EXTSZINHERIT  (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
+#define XFS_DIFLAG_NODEFRAG      (1 << XFS_DIFLAG_NODEFRAG_BIT)
 
 #define XFS_DIFLAG_ANY \
        (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
         XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
         XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
         XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
-        XFS_DIFLAG_EXTSZINHERIT)
+        XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG)
 
 #endif /* __XFS_DINODE_H__ */
diff --git a/fs/xfs/xfs_dir.c b/fs/xfs/xfs_dir.c
deleted file mode 100644 (file)
index 9cc702a..0000000
+++ /dev/null
@@ -1,1217 +0,0 @@
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_dir.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
-#include "xfs_mount.h"
-#include "xfs_da_btree.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_alloc.h"
-#include "xfs_btree.h"
-#include "xfs_dir_sf.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_bmap.h"
-#include "xfs_dir_leaf.h"
-#include "xfs_error.h"
-
-/*
- * xfs_dir.c
- *
- * Provide the external interfaces to manage directories.
- */
-
-/*========================================================================
- * Function prototypes for the kernel.
- *========================================================================*/
-
-/*
- * Functions for the dirops interfaces.
- */
-static void    xfs_dir_mount(struct xfs_mount *mp);
-
-static int     xfs_dir_isempty(struct xfs_inode *dp);
-
-static int     xfs_dir_init(struct xfs_trans *trans,
-                            struct xfs_inode *dir,
-                            struct xfs_inode *parent_dir);
-
-static int     xfs_dir_createname(struct xfs_trans *trans,
-                                  struct xfs_inode *dp,
-                                  char *name_string,
-                                  int name_len,
-                                  xfs_ino_t inode_number,
-                                  xfs_fsblock_t *firstblock,
-                                  xfs_bmap_free_t *flist,
-                                  xfs_extlen_t total);
-
-static int     xfs_dir_lookup(struct xfs_trans *tp,
-                              struct xfs_inode *dp,
-                              char *name_string,
-                              int name_length,
-                              xfs_ino_t *inode_number);
-
-static int     xfs_dir_removename(struct xfs_trans *trans,
-                                  struct xfs_inode *dp,
-                                  char *name_string,
-                                  int name_length,
-                                  xfs_ino_t ino,
-                                  xfs_fsblock_t *firstblock,
-                                  xfs_bmap_free_t *flist,
-                                  xfs_extlen_t total);
-
-static int     xfs_dir_getdents(struct xfs_trans *tp,
-                                struct xfs_inode *dp,
-                                struct uio *uiop,
-                                int *eofp);
-
-static int     xfs_dir_replace(struct xfs_trans *tp,
-                               struct xfs_inode *dp,
-                               char *name_string,
-                               int name_length,
-                               xfs_ino_t inode_number,
-                               xfs_fsblock_t *firstblock,
-                               xfs_bmap_free_t *flist,
-                               xfs_extlen_t total);
-
-static int     xfs_dir_canenter(struct xfs_trans *tp,
-                                struct xfs_inode *dp,
-                                char *name_string,
-                                int name_length);
-
-static int     xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp,
-                                                 xfs_dinode_t *dip);
-
-xfs_dirops_t xfsv1_dirops = {
-       .xd_mount                       = xfs_dir_mount,
-       .xd_isempty                     = xfs_dir_isempty,
-       .xd_init                        = xfs_dir_init,
-       .xd_createname                  = xfs_dir_createname,
-       .xd_lookup                      = xfs_dir_lookup,
-       .xd_removename                  = xfs_dir_removename,
-       .xd_getdents                    = xfs_dir_getdents,
-       .xd_replace                     = xfs_dir_replace,
-       .xd_canenter                    = xfs_dir_canenter,
-       .xd_shortform_validate_ondisk   = xfs_dir_shortform_validate_ondisk,
-       .xd_shortform_to_single         = xfs_dir_shortform_to_leaf,
-};
-
-/*
- * Internal routines when dirsize == XFS_LBSIZE(mp).
- */
-STATIC int xfs_dir_leaf_lookup(xfs_da_args_t *args);
-STATIC int xfs_dir_leaf_removename(xfs_da_args_t *args, int *number_entries,
-                                                int *total_namebytes);
-STATIC int xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp,
-                                            uio_t *uio, int *eofp,
-                                            xfs_dirent_t *dbp,
-                                            xfs_dir_put_t put);
-STATIC int xfs_dir_leaf_replace(xfs_da_args_t *args);
-
-/*
- * Internal routines when dirsize > XFS_LBSIZE(mp).
- */
-STATIC int xfs_dir_node_addname(xfs_da_args_t *args);
-STATIC int xfs_dir_node_lookup(xfs_da_args_t *args);
-STATIC int xfs_dir_node_removename(xfs_da_args_t *args);
-STATIC int xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp,
-                                            uio_t *uio, int *eofp,
-                                            xfs_dirent_t *dbp,
-                                            xfs_dir_put_t put);
-STATIC int xfs_dir_node_replace(xfs_da_args_t *args);
-
-#if defined(XFS_DIR_TRACE)
-ktrace_t *xfs_dir_trace_buf;
-#endif
-
-
-/*========================================================================
- * Overall external interface routines.
- *========================================================================*/
-
-xfs_dahash_t   xfs_dir_hash_dot, xfs_dir_hash_dotdot;
-
-/*
- * One-time startup routine called from xfs_init().
- */
-void
-xfs_dir_startup(void)
-{
-       xfs_dir_hash_dot = xfs_da_hashname(".", 1);
-       xfs_dir_hash_dotdot = xfs_da_hashname("..", 2);
-}
-
-/*
- * Initialize directory-related fields in the mount structure.
- */
-static void
-xfs_dir_mount(xfs_mount_t *mp)
-{
-       uint shortcount, leafcount, count;
-
-       mp->m_dirversion = 1;
-       if (!(mp->m_flags & XFS_MOUNT_ATTR2)) {
-               shortcount = (mp->m_attroffset -
-                               (uint)sizeof(xfs_dir_sf_hdr_t)) /
-                                (uint)sizeof(xfs_dir_sf_entry_t);
-               leafcount = (XFS_LBSIZE(mp) -
-                               (uint)sizeof(xfs_dir_leaf_hdr_t)) /
-                                ((uint)sizeof(xfs_dir_leaf_entry_t) +
-                                 (uint)sizeof(xfs_dir_leaf_name_t));
-       } else {
-               shortcount = (XFS_BMDR_SPACE_CALC(MINABTPTRS) -
-                             (uint)sizeof(xfs_dir_sf_hdr_t)) /
-                              (uint)sizeof(xfs_dir_sf_entry_t);
-               leafcount = (XFS_LBSIZE(mp) -
-                           (uint)sizeof(xfs_dir_leaf_hdr_t)) /
-                            ((uint)sizeof(xfs_dir_leaf_entry_t) +
-                             (uint)sizeof(xfs_dir_leaf_name_t));
-       }
-       count = shortcount > leafcount ? shortcount : leafcount;
-       mp->m_dircook_elog = xfs_da_log2_roundup(count + 1);
-       ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog);
-       mp->m_dir_node_ents = mp->m_attr_node_ents =
-               (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) /
-               (uint)sizeof(xfs_da_node_entry_t);
-       mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100;
-       mp->m_dirblksize = mp->m_sb.sb_blocksize;
-       mp->m_dirblkfsbs = 1;
-}
-
-/*
- * Return 1 if directory contains only "." and "..".
- */
-static int
-xfs_dir_isempty(xfs_inode_t *dp)
-{
-       xfs_dir_sf_hdr_t *hdr;
-
-       ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-       if (dp->i_d.di_size == 0)
-               return(1);
-       if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
-               return(0);
-       hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data;
-       return(hdr->count == 0);
-}
-
-/*
- * Initialize a directory with its "." and ".." entries.
- */
-static int
-xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir)
-{
-       xfs_da_args_t args;
-       int error;
-
-       memset((char *)&args, 0, sizeof(args));
-       args.dp = dir;
-       args.trans = trans;
-
-       ASSERT((dir->i_d.di_mode & S_IFMT) == S_IFDIR);
-       if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino)))
-               return error;
-
-       return(xfs_dir_shortform_create(&args, parent_dir->i_ino));
-}
-
-/*
- * Generic handler routine to add a name to a directory.
- * Transitions directory from shortform to Btree as necessary.
- */
-static int                                                     /* error */
-xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name,
-                  int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock,
-                  xfs_bmap_free_t *flist, xfs_extlen_t total)
-{
-       xfs_da_args_t args;
-       int retval, newsize, done;
-
-       ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-
-       if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum)))
-               return (retval);
-
-       XFS_STATS_INC(xs_dir_create);
-       /*
-        * Fill in the arg structure for this request.
-        */
-       args.name = name;
-       args.namelen = namelen;
-       args.hashval = xfs_da_hashname(name, namelen);
-       args.inumber = inum;
-       args.dp = dp;
-       args.firstblock = firstblock;
-       args.flist = flist;
-       args.total = total;
-       args.whichfork = XFS_DATA_FORK;
-       args.trans = trans;
-       args.justcheck = 0;
-       args.addname = args.oknoent = 1;
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       done = 0;
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen);
-               if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) {
-                       retval = xfs_dir_shortform_addname(&args);
-                       done = 1;
-               } else {
-                       if (total == 0)
-                               return XFS_ERROR(ENOSPC);
-                       retval = xfs_dir_shortform_to_leaf(&args);
-                       done = retval != 0;
-               }
-       }
-       if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
-               retval = xfs_dir_leaf_addname(&args);
-               done = retval != ENOSPC;
-               if (!done) {
-                       if (total == 0)
-                               return XFS_ERROR(ENOSPC);
-                       retval = xfs_dir_leaf_to_node(&args);
-                       done = retval != 0;
-               }
-       }
-       if (!done) {
-               retval = xfs_dir_node_addname(&args);
-       }
-       return(retval);
-}
-
-/*
- * Generic handler routine to check if a name can be added to a directory,
- * without adding any blocks to the directory.
- */
-static int                                                     /* error */
-xfs_dir_canenter(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen)
-{
-       xfs_da_args_t args;
-       int retval, newsize;
-
-       ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-       /*
-        * Fill in the arg structure for this request.
-        */
-       args.name = name;
-       args.namelen = namelen;
-       args.hashval = xfs_da_hashname(name, namelen);
-       args.inumber = 0;
-       args.dp = dp;
-       args.firstblock = NULL;
-       args.flist = NULL;
-       args.total = 0;
-       args.whichfork = XFS_DATA_FORK;
-       args.trans = trans;
-       args.justcheck = args.addname = args.oknoent = 1;
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen);
-               if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp))
-                       retval = 0;
-               else
-                       retval = XFS_ERROR(ENOSPC);
-       } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
-               retval = xfs_dir_leaf_addname(&args);
-       } else {
-               retval = xfs_dir_node_addname(&args);
-       }
-       return(retval);
-}
-
-/*
- * Generic handler routine to remove a name from a directory.
- * Transitions directory from Btree to shortform as necessary.
- */
-static int                                                     /* error */
-xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name,
-                  int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock,
-                  xfs_bmap_free_t *flist, xfs_extlen_t total)
-{
-       xfs_da_args_t args;
-       int count, totallen, newsize, retval;
-
-       ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-       XFS_STATS_INC(xs_dir_remove);
-       /*
-        * Fill in the arg structure for this request.
-        */
-       args.name = name;
-       args.namelen = namelen;
-       args.hashval = xfs_da_hashname(name, namelen);
-       args.inumber = ino;
-       args.dp = dp;
-       args.firstblock = firstblock;
-       args.flist = flist;
-       args.total = total;
-       args.whichfork = XFS_DATA_FORK;
-       args.trans = trans;
-       args.justcheck = args.addname = args.oknoent = 0;
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               retval = xfs_dir_shortform_removename(&args);
-       } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
-               retval = xfs_dir_leaf_removename(&args, &count, &totallen);
-               if (retval == 0) {
-                       newsize = XFS_DIR_SF_ALLFIT(count, totallen);
-                       if (newsize <= XFS_IFORK_DSIZE(dp)) {
-                               retval = xfs_dir_leaf_to_shortform(&args);
-                       }
-               }
-       } else {
-               retval = xfs_dir_node_removename(&args);
-       }
-       return(retval);
-}
-
-static int                                                     /* error */
-xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen,
-                                  xfs_ino_t *inum)
-{
-       xfs_da_args_t args;
-       int retval;
-
-       ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-
-       XFS_STATS_INC(xs_dir_lookup);
-       /*
-        * Fill in the arg structure for this request.
-        */
-       args.name = name;
-       args.namelen = namelen;
-       args.hashval = xfs_da_hashname(name, namelen);
-       args.inumber = 0;
-       args.dp = dp;
-       args.firstblock = NULL;
-       args.flist = NULL;
-       args.total = 0;
-       args.whichfork = XFS_DATA_FORK;
-       args.trans = trans;
-       args.justcheck = args.addname = 0;
-       args.oknoent = 1;
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               retval = xfs_dir_shortform_lookup(&args);
-       } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
-               retval = xfs_dir_leaf_lookup(&args);
-       } else {
-               retval = xfs_dir_node_lookup(&args);
-       }
-       if (retval == EEXIST)
-               retval = 0;
-       *inum = args.inumber;
-       return(retval);
-}
-
-/*
- * Implement readdir.
- */
-static int                                                     /* error */
-xfs_dir_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp)
-{
-       xfs_dirent_t *dbp;
-       int  alignment, retval;
-       xfs_dir_put_t put;
-
-       XFS_STATS_INC(xs_dir_getdents);
-       ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-
-       /*
-        * If our caller has given us a single contiguous memory buffer,
-        * just work directly within that buffer.  If it's in user memory,
-        * lock it down first.
-        */
-       alignment = sizeof(xfs_off_t) - 1;
-       if ((uio->uio_iovcnt == 1) &&
-           (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) &&
-           ((uio->uio_iov[0].iov_len & alignment) == 0)) {
-               dbp = NULL;
-               put = xfs_dir_put_dirent64_direct;
-       } else {
-               dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP);
-               put = xfs_dir_put_dirent64_uio;
-       }
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       *eofp = 0;
-
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               retval = xfs_dir_shortform_getdents(dp, uio, eofp, dbp, put);
-       } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
-               retval = xfs_dir_leaf_getdents(trans, dp, uio, eofp, dbp, put);
-       } else {
-               retval = xfs_dir_node_getdents(trans, dp, uio, eofp, dbp, put);
-       }
-       if (dbp != NULL)
-               kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);
-
-       return(retval);
-}
-
-static int                                                     /* error */
-xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen,
-                                   xfs_ino_t inum, xfs_fsblock_t *firstblock,
-                                   xfs_bmap_free_t *flist, xfs_extlen_t total)
-{
-       xfs_da_args_t args;
-       int retval;
-
-       ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-
-       if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum)))
-               return retval;
-
-       /*
-        * Fill in the arg structure for this request.
-        */
-       args.name = name;
-       args.namelen = namelen;
-       args.hashval = xfs_da_hashname(name, namelen);
-       args.inumber = inum;
-       args.dp = dp;
-       args.firstblock = firstblock;
-       args.flist = flist;
-       args.total = total;
-       args.whichfork = XFS_DATA_FORK;
-       args.trans = trans;
-       args.justcheck = args.addname = args.oknoent = 0;
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
-               retval = xfs_dir_shortform_replace(&args);
-       } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) {
-               retval = xfs_dir_leaf_replace(&args);
-       } else {
-               retval = xfs_dir_node_replace(&args);
-       }
-
-       return(retval);
-}
-
-static int
-xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp)
-{
-       xfs_ino_t               ino;
-       int                     namelen_sum;
-       int                     count;
-       xfs_dir_shortform_t     *sf;
-       xfs_dir_sf_entry_t      *sfe;
-       int                     i;
-
-
-
-       if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & S_IFMT) != S_IFDIR) {
-               return 0;
-       }
-       if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) {
-               return 0;
-       }
-       if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) {
-               xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p",
-                       dp);
-               return 1;
-       }
-       sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf);
-       ino = XFS_GET_DIR_INO8(sf->hdr.parent);
-       if (xfs_dir_ino_validate(mp, ino))
-               return 1;
-
-       count = sf->hdr.count;
-       if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) {
-               xfs_fs_cmn_err(CE_WARN, mp,
-                       "Invalid shortform count: dp 0x%p", dp);
-               return(1);
-       }
-
-       if (count == 0) {
-               return 0;
-       }
-
-       namelen_sum = 0;
-       sfe = &sf->list[0];
-       for (i = sf->hdr.count - 1; i >= 0; i--) {
-               ino = XFS_GET_DIR_INO8(sfe->inumber);
-               xfs_dir_ino_validate(mp, ino);
-               if (sfe->namelen >= XFS_LITINO(mp)) {
-                       xfs_fs_cmn_err(CE_WARN, mp,
-                               "Invalid shortform namelen: dp 0x%p", dp);
-                       return 1;
-               }
-               namelen_sum += sfe->namelen;
-               sfe = XFS_DIR_SF_NEXTENTRY(sfe);
-       }
-       if (namelen_sum >= XFS_LITINO(mp)) {
-               xfs_fs_cmn_err(CE_WARN, mp,
-                       "Invalid shortform namelen: dp 0x%p", dp);
-               return 1;
-       }
-
-       return 0;
-}
-
-/*========================================================================
- * External routines when dirsize == XFS_LBSIZE(dp->i_mount).
- *========================================================================*/
-
-/*
- * Add a name to the leaf directory structure
- * This is the external routine.
- */
-int
-xfs_dir_leaf_addname(xfs_da_args_t *args)
-{
-       int index, retval;
-       xfs_dabuf_t *bp;
-
-       retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
-                                             XFS_DATA_FORK);
-       if (retval)
-               return(retval);
-       ASSERT(bp != NULL);
-
-       retval = xfs_dir_leaf_lookup_int(bp, args, &index);
-       if (retval == ENOENT)
-               retval = xfs_dir_leaf_add(bp, args, index);
-       xfs_da_buf_done(bp);
-       return(retval);
-}
-
-/*
- * Remove a name from the leaf directory structure
- * This is the external routine.
- */
-STATIC int
-xfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen)
-{
-       xfs_dir_leafblock_t *leaf;
-       int index, retval;
-       xfs_dabuf_t *bp;
-
-       retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
-                                             XFS_DATA_FORK);
-       if (retval)
-               return(retval);
-       ASSERT(bp != NULL);
-       leaf = bp->data;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       retval = xfs_dir_leaf_lookup_int(bp, args, &index);
-       if (retval == EEXIST) {
-               (void)xfs_dir_leaf_remove(args->trans, bp, index);
-               *count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-               *totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
-               retval = 0;
-       }
-       xfs_da_buf_done(bp);
-       return(retval);
-}
-
-/*
- * Look up a name in a leaf directory structure.
- * This is the external routine.
- */
-STATIC int
-xfs_dir_leaf_lookup(xfs_da_args_t *args)
-{
-       int index, retval;
-       xfs_dabuf_t *bp;
-
-       retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
-                                             XFS_DATA_FORK);
-       if (retval)
-               return(retval);
-       ASSERT(bp != NULL);
-       retval = xfs_dir_leaf_lookup_int(bp, args, &index);
-       xfs_da_brelse(args->trans, bp);
-       return(retval);
-}
-
-/*
- * Copy out directory entries for getdents(), for leaf directories.
- */
-STATIC int
-xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio,
-                                 int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put)
-{
-       xfs_dabuf_t *bp;
-       int retval, eob;
-
-       retval = xfs_da_read_buf(dp->i_transp, dp, 0, -1, &bp, XFS_DATA_FORK);
-       if (retval)
-               return(retval);
-       ASSERT(bp != NULL);
-       retval = xfs_dir_leaf_getdents_int(bp, dp, 0, uio, &eob, dbp, put, -1);
-       xfs_da_brelse(trans, bp);
-       *eofp = (eob == 0);
-       return(retval);
-}
-
-/*
- * Look up a name in a leaf directory structure, replace the inode number.
- * This is the external routine.
- */
-STATIC int
-xfs_dir_leaf_replace(xfs_da_args_t *args)
-{
-       int index, retval;
-       xfs_dabuf_t *bp;
-       xfs_ino_t inum;
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_entry_t *entry;
-       xfs_dir_leaf_name_t *namest;
-
-       inum = args->inumber;
-       retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
-                                             XFS_DATA_FORK);
-       if (retval)
-               return(retval);
-       ASSERT(bp != NULL);
-       retval = xfs_dir_leaf_lookup_int(bp, args, &index);
-       if (retval == EEXIST) {
-               leaf = bp->data;
-               entry = &leaf->entries[index];
-               namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-               /* XXX - replace assert? */
-               XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber);
-               xfs_da_log_buf(args->trans, bp,
-                   XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber)));
-               xfs_da_buf_done(bp);
-               retval = 0;
-       } else
-               xfs_da_brelse(args->trans, bp);
-       return(retval);
-}
-
-
-/*========================================================================
- * External routines when dirsize > XFS_LBSIZE(mp).
- *========================================================================*/
-
-/*
- * Add a name to a Btree-format directory.
- *
- * This will involve walking down the Btree, and may involve splitting
- * leaf nodes and even splitting intermediate nodes up to and including
- * the root node (a special case of an intermediate node).
- */
-STATIC int
-xfs_dir_node_addname(xfs_da_args_t *args)
-{
-       xfs_da_state_t *state;
-       xfs_da_state_blk_t *blk;
-       int retval, error;
-
-       /*
-        * Fill in bucket of arguments/results/context to carry around.
-        */
-       state = xfs_da_state_alloc();
-       state->args = args;
-       state->mp = args->dp->i_mount;
-       state->blocksize = state->mp->m_sb.sb_blocksize;
-       state->node_ents = state->mp->m_dir_node_ents;
-
-       /*
-        * Search to see if name already exists, and get back a pointer
-        * to where it should go.
-        */
-       error = xfs_da_node_lookup_int(state, &retval);
-       if (error)
-               retval = error;
-       if (retval != ENOENT)
-               goto error;
-       blk = &state->path.blk[ state->path.active-1 ];
-       ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC);
-       retval = xfs_dir_leaf_add(blk->bp, args, blk->index);
-       if (retval == 0) {
-               /*
-                * Addition succeeded, update Btree hashvals.
-                */
-               if (!args->justcheck)
-                       xfs_da_fixhashpath(state, &state->path);
-       } else {
-               /*
-                * Addition failed, split as many Btree elements as required.
-                */
-               if (args->total == 0) {
-                       ASSERT(retval == ENOSPC);
-                       goto error;
-               }
-               retval = xfs_da_split(state);
-       }
-error:
-       xfs_da_state_free(state);
-
-       return(retval);
-}
-
-/*
- * Remove a name from a B-tree directory.
- *
- * This will involve walking down the Btree, and may involve joining
- * leaf nodes and even joining intermediate nodes up to and including
- * the root node (a special case of an intermediate node).
- */
-STATIC int
-xfs_dir_node_removename(xfs_da_args_t *args)
-{
-       xfs_da_state_t *state;
-       xfs_da_state_blk_t *blk;
-       int retval, error;
-
-       state = xfs_da_state_alloc();
-       state->args = args;
-       state->mp = args->dp->i_mount;
-       state->blocksize = state->mp->m_sb.sb_blocksize;
-       state->node_ents = state->mp->m_dir_node_ents;
-
-       /*
-        * Search to see if name exists, and get back a pointer to it.
-        */
-       error = xfs_da_node_lookup_int(state, &retval);
-       if (error)
-               retval = error;
-       if (retval != EEXIST) {
-               xfs_da_state_free(state);
-               return(retval);
-       }
-
-       /*
-        * Remove the name and update the hashvals in the tree.
-        */
-       blk = &state->path.blk[ state->path.active-1 ];
-       ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC);
-       retval = xfs_dir_leaf_remove(args->trans, blk->bp, blk->index);
-       xfs_da_fixhashpath(state, &state->path);
-
-       /*
-        * Check to see if the tree needs to be collapsed.
-        */
-       error = 0;
-       if (retval) {
-               error = xfs_da_join(state);
-       }
-
-       xfs_da_state_free(state);
-       if (error)
-               return(error);
-       return(0);
-}
-
-/*
- * Look up a filename in a int directory.
- * Use an internal routine to actually do all the work.
- */
-STATIC int
-xfs_dir_node_lookup(xfs_da_args_t *args)
-{
-       xfs_da_state_t *state;
-       int retval, error, i;
-
-       state = xfs_da_state_alloc();
-       state->args = args;
-       state->mp = args->dp->i_mount;
-       state->blocksize = state->mp->m_sb.sb_blocksize;
-       state->node_ents = state->mp->m_dir_node_ents;
-
-       /*
-        * Search to see if name exists,
-        * and get back a pointer to it.
-        */
-       error = xfs_da_node_lookup_int(state, &retval);
-       if (error) {
-               retval = error;
-       }
-
-       /*
-        * If not in a transaction, we have to release all the buffers.
-        */
-       for (i = 0; i < state->path.active; i++) {
-               xfs_da_brelse(args->trans, state->path.blk[i].bp);
-               state->path.blk[i].bp = NULL;
-       }
-
-       xfs_da_state_free(state);
-       return(retval);
-}
-
-STATIC int
-xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio,
-                                 int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put)
-{
-       xfs_da_intnode_t *node;
-       xfs_da_node_entry_t *btree;
-       xfs_dir_leafblock_t *leaf = NULL;
-       xfs_dablk_t bno, nextbno;
-       xfs_dahash_t cookhash;
-       xfs_mount_t *mp;
-       int error, eob, i;
-       xfs_dabuf_t *bp;
-       xfs_daddr_t nextda;
-
-       /*
-        * Pick up our context.
-        */
-       mp = dp->i_mount;
-       bp = NULL;
-       bno = XFS_DA_COOKIE_BNO(mp, uio->uio_offset);
-       cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset);
-
-       xfs_dir_trace_g_du("node: start", dp, uio);
-
-       /*
-        * Re-find our place, even if we're confused about what our place is.
-        *
-        * First we check the block number from the magic cookie, it is a
-        * cache of where we ended last time.  If we find a leaf block, and
-        * the starting hashval in that block is less than our desired
-        * hashval, then we run with it.
-        */
-       if (bno > 0) {
-               error = xfs_da_read_buf(trans, dp, bno, -2, &bp, XFS_DATA_FORK);
-               if ((error != 0) && (error != EFSCORRUPTED))
-                       return(error);
-               if (bp)
-                       leaf = bp->data;
-               if (bp && be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
-                       xfs_dir_trace_g_dub("node: block not a leaf",
-                                                  dp, uio, bno);
-                       xfs_da_brelse(trans, bp);
-                       bp = NULL;
-               }
-               if (bp && INT_GET(leaf->entries[0].hashval, ARCH_CONVERT) > cookhash) {
-                       xfs_dir_trace_g_dub("node: leaf hash too large",
-                                                  dp, uio, bno);
-                       xfs_da_brelse(trans, bp);
-                       bp = NULL;
-               }
-               if (bp &&
-                   cookhash > INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)) {
-                       xfs_dir_trace_g_dub("node: leaf hash too small",
-                                                  dp, uio, bno);
-                       xfs_da_brelse(trans, bp);
-                       bp = NULL;
-               }
-       }
-
-       /*
-        * If we did not find a leaf block from the blockno in the cookie,
-        * or we there was no blockno in the cookie (eg: first time thru),
-        * the we start at the top of the Btree and re-find our hashval.
-        */
-       if (bp == NULL) {
-               xfs_dir_trace_g_du("node: start at root" , dp, uio);
-               bno = 0;
-               for (;;) {
-                       error = xfs_da_read_buf(trans, dp, bno, -1, &bp,
-                                                      XFS_DATA_FORK);
-                       if (error)
-                               return(error);
-                       if (bp == NULL)
-                               return(XFS_ERROR(EFSCORRUPTED));
-                       node = bp->data;
-                       if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC)
-                               break;
-                       btree = &node->btree[0];
-                       xfs_dir_trace_g_dun("node: node detail", dp, uio, node);
-                       for (i = 0; i < be16_to_cpu(node->hdr.count); btree++, i++) {
-                               if (be32_to_cpu(btree->hashval) >= cookhash) {
-                                       bno = be32_to_cpu(btree->before);
-                                       break;
-                               }
-                       }
-                       if (i == be16_to_cpu(node->hdr.count)) {
-                               xfs_da_brelse(trans, bp);
-                               xfs_dir_trace_g_du("node: hash beyond EOF",
-                                                         dp, uio);
-                               uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0,
-                                                            XFS_DA_MAXHASH);
-                               *eofp = 1;
-                               return(0);
-                       }
-                       xfs_dir_trace_g_dub("node: going to block",
-                                                  dp, uio, bno);
-                       xfs_da_brelse(trans, bp);
-               }
-       }
-       ASSERT(cookhash != XFS_DA_MAXHASH);
-
-       /*
-        * We've dropped down to the (first) leaf block that contains the
-        * hashval we are interested in.  Continue rolling upward thru the
-        * leaf blocks until we fill up our buffer.
-        */
-       for (;;) {
-               leaf = bp->data;
-               if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)) {
-                       xfs_dir_trace_g_dul("node: not a leaf", dp, uio, leaf);
-                       xfs_da_brelse(trans, bp);
-                       XFS_CORRUPTION_ERROR("xfs_dir_node_getdents(1)",
-                                            XFS_ERRLEVEL_LOW, mp, leaf);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-               xfs_dir_trace_g_dul("node: leaf detail", dp, uio, leaf);
-               if ((nextbno = be32_to_cpu(leaf->hdr.info.forw))) {
-                       nextda = xfs_da_reada_buf(trans, dp, nextbno,
-                                                 XFS_DATA_FORK);
-               } else
-                       nextda = -1;
-               error = xfs_dir_leaf_getdents_int(bp, dp, bno, uio, &eob, dbp,
-                                                 put, nextda);
-               xfs_da_brelse(trans, bp);
-               bno = nextbno;
-               if (eob) {
-                       xfs_dir_trace_g_dub("node: E-O-B", dp, uio, bno);
-                       *eofp = 0;
-                       return(error);
-               }
-               if (bno == 0)
-                       break;
-               error = xfs_da_read_buf(trans, dp, bno, nextda, &bp,
-                                       XFS_DATA_FORK);
-               if (error)
-                       return(error);
-               if (unlikely(bp == NULL)) {
-                       XFS_ERROR_REPORT("xfs_dir_node_getdents(2)",
-                                        XFS_ERRLEVEL_LOW, mp);
-                       return(XFS_ERROR(EFSCORRUPTED));
-               }
-       }
-       *eofp = 1;
-       xfs_dir_trace_g_du("node: E-O-F", dp, uio);
-       return(0);
-}
-
-/*
- * Look up a filename in an int directory, replace the inode number.
- * Use an internal routine to actually do the lookup.
- */
-STATIC int
-xfs_dir_node_replace(xfs_da_args_t *args)
-{
-       xfs_da_state_t *state;
-       xfs_da_state_blk_t *blk;
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_entry_t *entry;
-       xfs_dir_leaf_name_t *namest;
-       xfs_ino_t inum;
-       int retval, error, i;
-       xfs_dabuf_t *bp;
-
-       state = xfs_da_state_alloc();
-       state->args = args;
-       state->mp = args->dp->i_mount;
-       state->blocksize = state->mp->m_sb.sb_blocksize;
-       state->node_ents = state->mp->m_dir_node_ents;
-       inum = args->inumber;
-
-       /*
-        * Search to see if name exists,
-        * and get back a pointer to it.
-        */
-       error = xfs_da_node_lookup_int(state, &retval);
-       if (error) {
-               retval = error;
-       }
-
-       if (retval == EEXIST) {
-               blk = &state->path.blk[state->path.active - 1];
-               ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC);
-               bp = blk->bp;
-               leaf = bp->data;
-               entry = &leaf->entries[blk->index];
-               namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-               /* XXX - replace assert ? */
-               XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber);
-               xfs_da_log_buf(args->trans, bp,
-                   XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber)));
-               xfs_da_buf_done(bp);
-               blk->bp = NULL;
-               retval = 0;
-       } else {
-               i = state->path.active - 1;
-               xfs_da_brelse(args->trans, state->path.blk[i].bp);
-               state->path.blk[i].bp = NULL;
-       }
-       for (i = 0; i < state->path.active - 1; i++) {
-               xfs_da_brelse(args->trans, state->path.blk[i].bp);
-               state->path.blk[i].bp = NULL;
-       }
-
-       xfs_da_state_free(state);
-       return(retval);
-}
-
-#if defined(XFS_DIR_TRACE)
-/*
- * Add a trace buffer entry for an inode and a uio.
- */
-void
-xfs_dir_trace_g_du(char *where, xfs_inode_t *dp, uio_t *uio)
-{
-       xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DU, where,
-                    (void *)dp, (void *)dp->i_mount,
-                    (void *)((unsigned long)(uio->uio_offset >> 32)),
-                    (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
-                    (void *)(unsigned long)uio->uio_resid,
-                    NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-}
-
-/*
- * Add a trace buffer entry for an inode and a uio.
- */
-void
-xfs_dir_trace_g_dub(char *where, xfs_inode_t *dp, uio_t *uio, xfs_dablk_t bno)
-{
-       xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUB, where,
-                    (void *)dp, (void *)dp->i_mount,
-                    (void *)((unsigned long)(uio->uio_offset >> 32)),
-                    (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
-                    (void *)(unsigned long)uio->uio_resid,
-                    (void *)(unsigned long)bno,
-                    NULL, NULL, NULL, NULL, NULL, NULL);
-}
-
-/*
- * Add a trace buffer entry for an inode and a uio.
- */
-void
-xfs_dir_trace_g_dun(char *where, xfs_inode_t *dp, uio_t *uio,
-                       xfs_da_intnode_t *node)
-{
-       int     last = be16_to_cpu(node->hdr.count) - 1;
-
-       xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUN, where,
-                    (void *)dp, (void *)dp->i_mount,
-                    (void *)((unsigned long)(uio->uio_offset >> 32)),
-                    (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
-                    (void *)(unsigned long)uio->uio_resid,
-                    (void *)(unsigned long)be32_to_cpu(node->hdr.info.forw),
-                    (void *)(unsigned long)
-                       be16_to_cpu(node->hdr.count),
-                    (void *)(unsigned long)
-                       be32_to_cpu(node->btree[0].hashval),
-                    (void *)(unsigned long)
-                       be32_to_cpu(node->btree[last].hashval),
-                    NULL, NULL, NULL);
-}
-
-/*
- * Add a trace buffer entry for an inode and a uio.
- */
-void
-xfs_dir_trace_g_dul(char *where, xfs_inode_t *dp, uio_t *uio,
-                       xfs_dir_leafblock_t *leaf)
-{
-       int     last = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1;
-
-       xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUL, where,
-                    (void *)dp, (void *)dp->i_mount,
-                    (void *)((unsigned long)(uio->uio_offset >> 32)),
-                    (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
-                    (void *)(unsigned long)uio->uio_resid,
-                    (void *)(unsigned long)be32_to_cpu(leaf->hdr.info.forw),
-                    (void *)(unsigned long)
-                       INT_GET(leaf->hdr.count, ARCH_CONVERT),
-                    (void *)(unsigned long)
-                       INT_GET(leaf->entries[0].hashval, ARCH_CONVERT),
-                    (void *)(unsigned long)
-                       INT_GET(leaf->entries[last].hashval, ARCH_CONVERT),
-                    NULL, NULL, NULL);
-}
-
-/*
- * Add a trace buffer entry for an inode and a uio.
- */
-void
-xfs_dir_trace_g_due(char *where, xfs_inode_t *dp, uio_t *uio,
-                       xfs_dir_leaf_entry_t *entry)
-{
-       xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUE, where,
-                    (void *)dp, (void *)dp->i_mount,
-                    (void *)((unsigned long)(uio->uio_offset >> 32)),
-                    (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
-                    (void *)(unsigned long)uio->uio_resid,
-                    (void *)(unsigned long)
-                       INT_GET(entry->hashval, ARCH_CONVERT),
-                    NULL, NULL, NULL, NULL, NULL, NULL);
-}
-
-/*
- * Add a trace buffer entry for an inode and a uio.
- */
-void
-xfs_dir_trace_g_duc(char *where, xfs_inode_t *dp, uio_t *uio, xfs_off_t cookie)
-{
-       xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUC, where,
-                    (void *)dp, (void *)dp->i_mount,
-                    (void *)((unsigned long)(uio->uio_offset >> 32)),
-                    (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)),
-                    (void *)(unsigned long)uio->uio_resid,
-                    (void *)((unsigned long)(cookie >> 32)),
-                    (void *)((unsigned long)(cookie & 0xFFFFFFFF)),
-                    NULL, NULL, NULL, NULL, NULL);
-}
-
-/*
- * Add a trace buffer entry for the arguments given to the routine,
- * generic form.
- */
-void
-xfs_dir_trace_enter(int type, char *where,
-                       void * a0, void * a1,
-                       void * a2, void * a3,
-                       void * a4, void * a5,
-                       void * a6, void * a7,
-                       void * a8, void * a9,
-                       void * a10, void * a11)
-{
-       ASSERT(xfs_dir_trace_buf);
-       ktrace_enter(xfs_dir_trace_buf, (void *)(unsigned long)type,
-                                       (void *)where,
-                                       (void *)a0, (void *)a1, (void *)a2,
-                                       (void *)a3, (void *)a4, (void *)a5,
-                                       (void *)a6, (void *)a7, (void *)a8,
-                                       (void *)a9, (void *)a10, (void *)a11,
-                                       NULL, NULL);
-}
-#endif /* XFS_DIR_TRACE */
diff --git a/fs/xfs/xfs_dir.h b/fs/xfs/xfs_dir.h
deleted file mode 100644 (file)
index 8cc8afb..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2000,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef __XFS_DIR_H__
-#define        __XFS_DIR_H__
-
-/*
- * Large directories are structured around Btrees where all the data
- * elements are in the leaf nodes.  Filenames are hashed into an int,
- * then that int is used as the index into the Btree.  Since the hashval
- * of a filename may not be unique, we may have duplicate keys.  The
- * internal links in the Btree are logical block offsets into the file.
- *
- * Small directories use a different format and are packed as tightly
- * as possible so as to fit into the literal area of the inode.
- */
-
-/*========================================================================
- * Function prototypes for the kernel.
- *========================================================================*/
-
-struct uio;
-struct xfs_bmap_free;
-struct xfs_da_args;
-struct xfs_dinode;
-struct xfs_inode;
-struct xfs_mount;
-struct xfs_trans;
-
-/*
- * Directory function types.
- * Put in structures (xfs_dirops_t) for v1 and v2 directories.
- */
-typedef void   (*xfs_dir_mount_t)(struct xfs_mount *mp);
-typedef int    (*xfs_dir_isempty_t)(struct xfs_inode *dp);
-typedef int    (*xfs_dir_init_t)(struct xfs_trans *tp,
-                                 struct xfs_inode *dp,
-                                 struct xfs_inode *pdp);
-typedef int    (*xfs_dir_createname_t)(struct xfs_trans *tp,
-                                       struct xfs_inode *dp,
-                                       char *name,
-                                       int namelen,
-                                       xfs_ino_t inum,
-                                       xfs_fsblock_t *first,
-                                       struct xfs_bmap_free *flist,
-                                       xfs_extlen_t total);
-typedef int    (*xfs_dir_lookup_t)(struct xfs_trans *tp,
-                                   struct xfs_inode *dp,
-                                   char *name,
-                                   int namelen,
-                                   xfs_ino_t *inum);
-typedef int    (*xfs_dir_removename_t)(struct xfs_trans *tp,
-                                       struct xfs_inode *dp,
-                                       char *name,
-                                       int namelen,
-                                       xfs_ino_t ino,
-                                       xfs_fsblock_t *first,
-                                       struct xfs_bmap_free *flist,
-                                       xfs_extlen_t total);
-typedef int    (*xfs_dir_getdents_t)(struct xfs_trans *tp,
-                                     struct xfs_inode *dp,
-                                     struct uio *uio,
-                                     int *eofp);
-typedef int    (*xfs_dir_replace_t)(struct xfs_trans *tp,
-                                    struct xfs_inode *dp,
-                                    char *name,
-                                    int namelen,
-                                    xfs_ino_t inum,
-                                    xfs_fsblock_t *first,
-                                    struct xfs_bmap_free *flist,
-                                    xfs_extlen_t total);
-typedef int    (*xfs_dir_canenter_t)(struct xfs_trans *tp,
-                                     struct xfs_inode *dp,
-                                     char *name,
-                                     int namelen);
-typedef int    (*xfs_dir_shortform_validate_ondisk_t)(struct xfs_mount *mp,
-                                                      struct xfs_dinode *dip);
-typedef int    (*xfs_dir_shortform_to_single_t)(struct xfs_da_args *args);
-
-typedef struct xfs_dirops {
-       xfs_dir_mount_t                         xd_mount;
-       xfs_dir_isempty_t                       xd_isempty;
-       xfs_dir_init_t                          xd_init;
-       xfs_dir_createname_t                    xd_createname;
-       xfs_dir_lookup_t                        xd_lookup;
-       xfs_dir_removename_t                    xd_removename;
-       xfs_dir_getdents_t                      xd_getdents;
-       xfs_dir_replace_t                       xd_replace;
-       xfs_dir_canenter_t                      xd_canenter;
-       xfs_dir_shortform_validate_ondisk_t     xd_shortform_validate_ondisk;
-       xfs_dir_shortform_to_single_t           xd_shortform_to_single;
-} xfs_dirops_t;
-
-/*
- * Overall external interface routines.
- */
-void   xfs_dir_startup(void);  /* called exactly once */
-
-#define        XFS_DIR_MOUNT(mp)       \
-       ((mp)->m_dirops.xd_mount(mp))
-#define        XFS_DIR_ISEMPTY(mp,dp)  \
-       ((mp)->m_dirops.xd_isempty(dp))
-#define        XFS_DIR_INIT(mp,tp,dp,pdp)      \
-       ((mp)->m_dirops.xd_init(tp,dp,pdp))
-#define        XFS_DIR_CREATENAME(mp,tp,dp,name,namelen,inum,first,flist,total) \
-       ((mp)->m_dirops.xd_createname(tp,dp,name,namelen,inum,first,flist,\
-                                     total))
-#define        XFS_DIR_LOOKUP(mp,tp,dp,name,namelen,inum)      \
-       ((mp)->m_dirops.xd_lookup(tp,dp,name,namelen,inum))
-#define        XFS_DIR_REMOVENAME(mp,tp,dp,name,namelen,ino,first,flist,total) \
-       ((mp)->m_dirops.xd_removename(tp,dp,name,namelen,ino,first,flist,total))
-#define        XFS_DIR_GETDENTS(mp,tp,dp,uio,eofp)     \
-       ((mp)->m_dirops.xd_getdents(tp,dp,uio,eofp))
-#define        XFS_DIR_REPLACE(mp,tp,dp,name,namelen,inum,first,flist,total)   \
-       ((mp)->m_dirops.xd_replace(tp,dp,name,namelen,inum,first,flist,total))
-#define        XFS_DIR_CANENTER(mp,tp,dp,name,namelen) \
-       ((mp)->m_dirops.xd_canenter(tp,dp,name,namelen))
-#define        XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp,dip)       \
-       ((mp)->m_dirops.xd_shortform_validate_ondisk(mp,dip))
-#define        XFS_DIR_SHORTFORM_TO_SINGLE(mp,args)    \
-       ((mp)->m_dirops.xd_shortform_to_single(args))
-
-#define        XFS_DIR_IS_V1(mp)       ((mp)->m_dirversion == 1)
-#define        XFS_DIR_IS_V2(mp)       ((mp)->m_dirversion == 2)
-extern xfs_dirops_t xfsv1_dirops;
-extern xfs_dirops_t xfsv2_dirops;
-
-#endif /* __XFS_DIR_H__ */
index 022c8398ab62d582786f9e90d3c27052d7295ee9..8edbe1adb95ba64b1ae75e135a9828ca43a3b0e8 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
-#include "xfs_dir_leaf.h"
 #include "xfs_dir2_data.h"
 #include "xfs_dir2_leaf.h"
 #include "xfs_dir2_block.h"
 #include "xfs_dir2_trace.h"
 #include "xfs_error.h"
 
-/*
- * Declarations for interface routines.
- */
-static void    xfs_dir2_mount(xfs_mount_t *mp);
-static int     xfs_dir2_isempty(xfs_inode_t *dp);
-static int     xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp,
-                             xfs_inode_t *pdp);
-static int     xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp,
-                                   char *name, int namelen, xfs_ino_t inum,
-                                   xfs_fsblock_t *first,
-                                   xfs_bmap_free_t *flist, xfs_extlen_t total);
-static int     xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
-                               int namelen, xfs_ino_t *inum);
-static int     xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp,
-                                   char *name, int namelen, xfs_ino_t ino,
-                                   xfs_fsblock_t *first,
-                                   xfs_bmap_free_t *flist, xfs_extlen_t total);
-static int     xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio,
-                                 int *eofp);
-static int     xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
-                                int namelen, xfs_ino_t inum,
-                                xfs_fsblock_t *first, xfs_bmap_free_t *flist,
-                                xfs_extlen_t total);
-static int     xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
-                                 int namelen);
-static int     xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp,
-                                                  xfs_dinode_t *dip);
-
-/*
- * Utility routine declarations.
- */
 static int     xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa);
 static int     xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa);
 
-/*
- * Directory operations vector.
- */
-xfs_dirops_t   xfsv2_dirops = {
-       .xd_mount                       = xfs_dir2_mount,
-       .xd_isempty                     = xfs_dir2_isempty,
-       .xd_init                        = xfs_dir2_init,
-       .xd_createname                  = xfs_dir2_createname,
-       .xd_lookup                      = xfs_dir2_lookup,
-       .xd_removename                  = xfs_dir2_removename,
-       .xd_getdents                    = xfs_dir2_getdents,
-       .xd_replace                     = xfs_dir2_replace,
-       .xd_canenter                    = xfs_dir2_canenter,
-       .xd_shortform_validate_ondisk   = xfs_dir2_shortform_validate_ondisk,
-       .xd_shortform_to_single         = xfs_dir2_sf_to_block,
-};
-
-/*
- * Interface routines.
- */
-
-/*
- * Initialize directory-related fields in the mount structure.
- */
-static void
-xfs_dir2_mount(
-       xfs_mount_t     *mp)            /* filesystem mount point */
+void
+xfs_dir_mount(
+       xfs_mount_t     *mp)
 {
-       mp->m_dirversion = 2;
+       ASSERT(XFS_SB_VERSION_HASDIRV2(&mp->m_sb));
        ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
               XFS_MAX_BLOCKSIZE);
        mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
@@ -128,73 +70,99 @@ xfs_dir2_mount(
 /*
  * Return 1 if directory contains only "." and "..".
  */
-static int                             /* return code */
-xfs_dir2_isempty(
-       xfs_inode_t     *dp)            /* incore inode structure */
+int
+xfs_dir_isempty(
+       xfs_inode_t     *dp)
 {
-       xfs_dir2_sf_t   *sfp;           /* shortform directory structure */
+       xfs_dir2_sf_t   *sfp;
 
        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-       /*
-        * Might happen during shutdown.
-        */
-       if (dp->i_d.di_size == 0) {
+       if (dp->i_d.di_size == 0)       /* might happen during shutdown. */
                return 1;
-       }
        if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
                return 0;
        sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
        return !sfp->hdr.count;
 }
 
+/*
+ * Validate a given inode number.
+ */
+int
+xfs_dir_ino_validate(
+       xfs_mount_t     *mp,
+       xfs_ino_t       ino)
+{
+       xfs_agblock_t   agblkno;
+       xfs_agino_t     agino;
+       xfs_agnumber_t  agno;
+       int             ino_ok;
+       int             ioff;
+
+       agno = XFS_INO_TO_AGNO(mp, ino);
+       agblkno = XFS_INO_TO_AGBNO(mp, ino);
+       ioff = XFS_INO_TO_OFFSET(mp, ino);
+       agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff);
+       ino_ok =
+               agno < mp->m_sb.sb_agcount &&
+               agblkno < mp->m_sb.sb_agblocks &&
+               agblkno != 0 &&
+               ioff < (1 << mp->m_sb.sb_inopblog) &&
+               XFS_AGINO_TO_INO(mp, agno, agino) == ino;
+       if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
+                       XFS_RANDOM_DIR_INO_VALIDATE))) {
+               xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
+                               (unsigned long long) ino);
+               XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+       return 0;
+}
+
 /*
  * Initialize a directory with its "." and ".." entries.
  */
-static int                             /* error */
-xfs_dir2_init(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
-       xfs_inode_t     *pdp)           /* incore parent directory inode */
+int
+xfs_dir_init(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
+       xfs_inode_t     *pdp)
 {
-       xfs_da_args_t   args;           /* operation arguments */
-       int             error;          /* error return value */
+       xfs_da_args_t   args;
+       int             error;
 
        memset((char *)&args, 0, sizeof(args));
        args.dp = dp;
        args.trans = tp;
        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-       if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) {
+       if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino)))
                return error;
-       }
        return xfs_dir2_sf_create(&args, pdp->i_ino);
 }
 
 /*
   Enter a name in a directory.
  */
-static int                                     /* error */
-xfs_dir2_createname(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_inode_t             *dp,            /* incore directory inode */
-       char                    *name,          /* new entry name */
-       int                     namelen,        /* new entry name length */
+int
+xfs_dir_createname(
+       xfs_trans_t             *tp,
+       xfs_inode_t             *dp,
+       char                    *name,
+       int                     namelen,
        xfs_ino_t               inum,           /* new entry inode number */
        xfs_fsblock_t           *first,         /* bmap's firstblock */
        xfs_bmap_free_t         *flist,         /* bmap's freeblock list */
        xfs_extlen_t            total)          /* bmap's total block count */
 {
-       xfs_da_args_t           args;           /* operation arguments */
-       int                     rval;           /* return value */
+       xfs_da_args_t           args;
+       int                     rval;
        int                     v;              /* type-checking value */
 
        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-       if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
+       if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
                return rval;
-       }
        XFS_STATS_INC(xs_dir_create);
-       /*
-        * Fill in the arg structure for this request.
-        */
+
        args.name = name;
        args.namelen = namelen;
        args.hashval = xfs_da_hashname(name, namelen);
@@ -207,18 +175,16 @@ xfs_dir2_createname(
        args.trans = tp;
        args.justcheck = 0;
        args.addname = args.oknoent = 1;
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
+
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_addname(&args);
-       else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_block_addname(&args);
-       else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_leaf_addname(&args);
        else
                rval = xfs_dir2_node_addname(&args);
@@ -228,24 +194,21 @@ xfs_dir2_createname(
 /*
  * Lookup a name in a directory, give back the inode number.
  */
-static int                             /* error */
-xfs_dir2_lookup(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
-       char            *name,          /* lookup name */
-       int             namelen,        /* lookup name length */
+int
+xfs_dir_lookup(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
+       char            *name,
+       int             namelen,
        xfs_ino_t       *inum)          /* out: inode number */
 {
-       xfs_da_args_t   args;           /* operation arguments */
-       int             rval;           /* return value */
+       xfs_da_args_t   args;
+       int             rval;
        int             v;              /* type-checking value */
 
        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
        XFS_STATS_INC(xs_dir_lookup);
 
-       /*
-        * Fill in the arg structure for this request.
-        */
        args.name = name;
        args.namelen = namelen;
        args.hashval = xfs_da_hashname(name, namelen);
@@ -258,18 +221,16 @@ xfs_dir2_lookup(
        args.trans = tp;
        args.justcheck = args.addname = 0;
        args.oknoent = 1;
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
+
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_lookup(&args);
-       else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_block_lookup(&args);
-       else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_leaf_lookup(&args);
        else
                rval = xfs_dir2_node_lookup(&args);
@@ -283,26 +244,24 @@ xfs_dir2_lookup(
 /*
  * Remove an entry from a directory.
  */
-static int                             /* error */
-xfs_dir2_removename(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
-       char            *name,          /* name of entry to remove */
-       int             namelen,        /* name length of entry to remove */
-       xfs_ino_t       ino,            /* inode number of entry to remove */
+int
+xfs_dir_removename(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
+       char            *name,
+       int             namelen,
+       xfs_ino_t       ino,
        xfs_fsblock_t   *first,         /* bmap's firstblock */
        xfs_bmap_free_t *flist,         /* bmap's freeblock list */
        xfs_extlen_t    total)          /* bmap's total block count */
 {
-       xfs_da_args_t   args;           /* operation arguments */
-       int             rval;           /* return value */
+       xfs_da_args_t   args;
+       int             rval;
        int             v;              /* type-checking value */
 
        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
        XFS_STATS_INC(xs_dir_remove);
-       /*
-        * Fill in the arg structure for this request.
-        */
+
        args.name = name;
        args.namelen = namelen;
        args.hashval = xfs_da_hashname(name, namelen);
@@ -314,18 +273,16 @@ xfs_dir2_removename(
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
        args.justcheck = args.addname = args.oknoent = 0;
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
+
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_removename(&args);
-       else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_block_removename(&args);
-       else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_leaf_removename(&args);
        else
                rval = xfs_dir2_node_removename(&args);
@@ -335,10 +292,10 @@ xfs_dir2_removename(
 /*
  * Read a directory.
  */
-static int                             /* error */
-xfs_dir2_getdents(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
+int
+xfs_dir_getdents(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
        uio_t           *uio,           /* caller's buffer control */
        int             *eofp)          /* out: eof reached */
 {
@@ -367,14 +324,11 @@ xfs_dir2_getdents(
        }
 
        *eofp = 0;
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put);
-       else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
                ;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put);
        else
                rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put);
@@ -386,29 +340,26 @@ xfs_dir2_getdents(
 /*
  * Replace the inode number of a directory entry.
  */
-static int                             /* error */
-xfs_dir2_replace(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
+int
+xfs_dir_replace(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
        char            *name,          /* name of entry to replace */
-       int             namelen,        /* name length of entry to replace */
+       int             namelen,
        xfs_ino_t       inum,           /* new inode number */
        xfs_fsblock_t   *first,         /* bmap's firstblock */
        xfs_bmap_free_t *flist,         /* bmap's freeblock list */
        xfs_extlen_t    total)          /* bmap's total block count */
 {
-       xfs_da_args_t   args;           /* operation arguments */
-       int             rval;           /* return value */
+       xfs_da_args_t   args;
+       int             rval;
        int             v;              /* type-checking value */
 
        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
-       if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
+       if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
                return rval;
-       }
-       /*
-        * Fill in the arg structure for this request.
-        */
+
        args.name = name;
        args.namelen = namelen;
        args.hashval = xfs_da_hashname(name, namelen);
@@ -420,18 +371,16 @@ xfs_dir2_replace(
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
        args.justcheck = args.addname = args.oknoent = 0;
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
+
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_replace(&args);
-       else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_block_replace(&args);
-       else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_leaf_replace(&args);
        else
                rval = xfs_dir2_node_replace(&args);
@@ -441,21 +390,19 @@ xfs_dir2_replace(
 /*
  * See if this entry can be added to the directory without allocating space.
  */
-static int                             /* error */
-xfs_dir2_canenter(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
+int
+xfs_dir_canenter(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
        char            *name,          /* name of entry to add */
-       int             namelen)        /* name length of entry to add */
+       int             namelen)
 {
-       xfs_da_args_t   args;           /* operation arguments */
-       int             rval;           /* return value */
+       xfs_da_args_t   args;
+       int             rval;
        int             v;              /* type-checking value */
 
        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
-       /*
-        * Fill in the arg structure for this request.
-        */
+
        args.name = name;
        args.namelen = namelen;
        args.hashval = xfs_da_hashname(name, namelen);
@@ -467,37 +414,22 @@ xfs_dir2_canenter(
        args.whichfork = XFS_DATA_FORK;
        args.trans = tp;
        args.justcheck = args.addname = args.oknoent = 1;
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
+
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
                rval = xfs_dir2_sf_addname(&args);
-       else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_block_addname(&args);
-       else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
+       else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
                return rval;
-       else if (v)
+       else if (v)
                rval = xfs_dir2_leaf_addname(&args);
        else
                rval = xfs_dir2_node_addname(&args);
        return rval;
 }
 
-/*
- * Dummy routine for shortform inode validation.
- * Can't really do this.
- */
-/* ARGSUSED */
-static int                             /* error */
-xfs_dir2_shortform_validate_ondisk(
-       xfs_mount_t     *mp,            /* filesystem mount point */
-       xfs_dinode_t    *dip)           /* ondisk inode */
-{
-       return 0;
-}
-
 /*
  * Utility routines.
  */
@@ -507,24 +439,24 @@ xfs_dir2_shortform_validate_ondisk(
  * This routine is for data and free blocks, not leaf/node blocks
  * which are handled by xfs_da_grow_inode.
  */
-int                                    /* error */
+int
 xfs_dir2_grow_inode(
-       xfs_da_args_t   *args,          /* operation arguments */
+       xfs_da_args_t   *args,
        int             space,          /* v2 dir's space XFS_DIR2_xxx_SPACE */
        xfs_dir2_db_t   *dbp)           /* out: block number added */
 {
        xfs_fileoff_t   bno;            /* directory offset of new block */
        int             count;          /* count of filesystem blocks */
        xfs_inode_t     *dp;            /* incore directory inode */
-       int             error;          /* error return value */
+       int             error;
        int             got;            /* blocks actually mapped */
-       int             i;              /* temp mapping index */
+       int             i;
        xfs_bmbt_irec_t map;            /* single structure for bmap */
        int             mapi;           /* mapping index */
        xfs_bmbt_irec_t *mapp;          /* bmap mapping structure(s) */
-       xfs_mount_t     *mp;            /* filesystem mount point */
+       xfs_mount_t     *mp;
        int             nmap;           /* number of bmap entries */
-       xfs_trans_t     *tp;            /* transaction pointer */
+       xfs_trans_t     *tp;
 
        xfs_dir2_trace_args_s("grow_inode", args, space);
        dp = args->dp;
@@ -538,9 +470,8 @@ xfs_dir2_grow_inode(
        /*
         * Find the first hole for our block.
         */
-       if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) {
+       if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK)))
                return error;
-       }
        nmap = 1;
        ASSERT(args->firstblock != NULL);
        /*
@@ -549,13 +480,9 @@ xfs_dir2_grow_inode(
        if ((error = xfs_bmapi(tp, dp, bno, count,
                        XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
                        args->firstblock, args->total, &map, &nmap,
-                       args->flist))) {
+                       args->flist, NULL)))
                return error;
-       }
        ASSERT(nmap <= 1);
-       /*
-        * Got it in 1.
-        */
        if (nmap == 1) {
                mapp = &map;
                mapi = 1;
@@ -585,7 +512,8 @@ xfs_dir2_grow_inode(
                        if ((error = xfs_bmapi(tp, dp, b, c,
                                        XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
                                        args->firstblock, args->total,
-                                       &mapp[mapi], &nmap, args->flist))) {
+                                       &mapp[mapi], &nmap, args->flist,
+                                       NULL))) {
                                kmem_free(mapp, sizeof(*mapp) * count);
                                return error;
                        }
@@ -645,20 +573,19 @@ xfs_dir2_grow_inode(
 /*
  * See if the directory is a single-block form directory.
  */
-int                                    /* error */
+int
 xfs_dir2_isblock(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
        int             *vp)            /* out: 1 is block, 0 is not block */
 {
        xfs_fileoff_t   last;           /* last file offset */
-       xfs_mount_t     *mp;            /* filesystem mount point */
-       int             rval;           /* return value */
+       xfs_mount_t     *mp;
+       int             rval;
 
        mp = dp->i_mount;
-       if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
+       if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
                return rval;
-       }
        rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
        ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
        *vp = rval;
@@ -668,20 +595,19 @@ xfs_dir2_isblock(
 /*
  * See if the directory is a single-leaf form directory.
  */
-int                                    /* error */
+int
 xfs_dir2_isleaf(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_inode_t     *dp,            /* incore directory inode */
+       xfs_trans_t     *tp,
+       xfs_inode_t     *dp,
        int             *vp)            /* out: 1 is leaf, 0 is not leaf */
 {
        xfs_fileoff_t   last;           /* last file offset */
-       xfs_mount_t     *mp;            /* filesystem mount point */
-       int             rval;           /* return value */
+       xfs_mount_t     *mp;
+       int             rval;
 
        mp = dp->i_mount;
-       if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
+       if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
                return rval;
-       }
        *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
        return 0;
 }
@@ -689,9 +615,9 @@ xfs_dir2_isleaf(
 /*
  * Getdents put routine for 64-bit ABI, direct form.
  */
-static int                                     /* error */
+static int
 xfs_dir2_put_dirent64_direct(
-       xfs_dir2_put_args_t     *pa)            /* argument bundle */
+       xfs_dir2_put_args_t     *pa)
 {
        xfs_dirent_t            *idbp;          /* dirent pointer */
        iovec_t                 *iovp;          /* io vector */
@@ -726,9 +652,9 @@ xfs_dir2_put_dirent64_direct(
 /*
  * Getdents put routine for 64-bit ABI, uio form.
  */
-static int                                     /* error */
+static int
 xfs_dir2_put_dirent64_uio(
-       xfs_dir2_put_args_t     *pa)            /* argument bundle */
+       xfs_dir2_put_args_t     *pa)
 {
        xfs_dirent_t            *idbp;          /* dirent pointer */
        int                     namelen;        /* entry name length */
@@ -764,17 +690,17 @@ xfs_dir2_put_dirent64_uio(
  */
 int
 xfs_dir2_shrink_inode(
-       xfs_da_args_t   *args,          /* operation arguments */
-       xfs_dir2_db_t   db,             /* directory block number */
-       xfs_dabuf_t     *bp)            /* block's buffer */
+       xfs_da_args_t   *args,
+       xfs_dir2_db_t   db,
+       xfs_dabuf_t     *bp)
 {
        xfs_fileoff_t   bno;            /* directory file offset */
        xfs_dablk_t     da;             /* directory file offset */
        int             done;           /* bunmap is finished */
-       xfs_inode_t     *dp;            /* incore directory inode */
-       int             error;          /* error return value */
-       xfs_mount_t     *mp;            /* filesystem mount point */
-       xfs_trans_t     *tp;            /* transaction pointer */
+       xfs_inode_t     *dp;
+       int             error;
+       xfs_mount_t     *mp;
+       xfs_trans_t     *tp;
 
        xfs_dir2_trace_args_db("shrink_inode", args, db, bp);
        dp = args->dp;
@@ -786,7 +712,7 @@ xfs_dir2_shrink_inode(
         */
        if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
                        XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
-                       &done))) {
+                       NULL, &done))) {
                /*
                 * ENOSPC actually can happen if we're in a removename with
                 * no space reservation, and the resulting block removal
index 7dd364b1e038d04053f525da93afd1e9687b3d61..86560b6f794cbaf0953d5d152b1c01fce6e606af 100644 (file)
@@ -22,7 +22,9 @@ struct uio;
 struct xfs_dabuf;
 struct xfs_da_args;
 struct xfs_dir2_put_args;
+struct xfs_bmap_free;
 struct xfs_inode;
+struct xfs_mount;
 struct xfs_trans;
 
 /*
@@ -73,7 +75,35 @@ typedef struct xfs_dir2_put_args {
 } xfs_dir2_put_args_t;
 
 /*
- * Other interfaces used by the rest of the dir v2 code.
+ * Generic directory interface routines
+ */
+extern void xfs_dir_startup(void);
+extern void xfs_dir_mount(struct xfs_mount *mp);
+extern int xfs_dir_isempty(struct xfs_inode *dp);
+extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
+                               struct xfs_inode *pdp);
+extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
+                               char *name, int namelen, xfs_ino_t inum,
+                               xfs_fsblock_t *first,
+                               struct xfs_bmap_free *flist, xfs_extlen_t tot);
+extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
+                               char *name, int namelen, xfs_ino_t *inum);
+extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
+                               char *name, int namelen, xfs_ino_t ino,
+                               xfs_fsblock_t *first,
+                               struct xfs_bmap_free *flist, xfs_extlen_t tot);
+extern int xfs_dir_getdents(struct xfs_trans *tp, struct xfs_inode *dp,
+                               uio_t *uio, int *eofp);
+extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
+                               char *name, int namelen, xfs_ino_t inum,
+                               xfs_fsblock_t *first,
+                               struct xfs_bmap_free *flist, xfs_extlen_t tot);
+extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
+                               char *name, int namelen);
+extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
+
+/*
+ * Utility routines for v2 directories.
  */
 extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
                                xfs_dir2_db_t *dbp);
index 972ded595476982dbb960e54245e01bcd86b477a..9d7438bba30d73b0c16ddb8686db9fd0fd6d5f70 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
-#include "xfs_dir_leaf.h"
 #include "xfs_dir2_data.h"
 #include "xfs_dir2_leaf.h"
 #include "xfs_dir2_block.h"
@@ -51,6 +48,18 @@ static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **bpp,
                                     int *entno);
 static int xfs_dir2_block_sort(const void *a, const void *b);
 
+static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot;
+
+/*
+ * One-time startup routine called from xfs_init().
+ */
+void
+xfs_dir_startup(void)
+{
+       xfs_dir_hash_dot = xfs_da_hashname(".", 1);
+       xfs_dir_hash_dotdot = xfs_da_hashname("..", 2);
+}
+
 /*
  * Add an entry to a block directory.
  */
@@ -400,7 +409,7 @@ xfs_dir2_block_addname(
        /*
         * Create the new data entry.
         */
-       INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+       dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, args->namelen);
        tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
@@ -508,7 +517,7 @@ xfs_dir2_block_getdents(
 
                p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
                                                    ptr - (char *)block);
-               p.ino = INT_GET(dep->inumber, ARCH_CONVERT);
+               p.ino = be64_to_cpu(dep->inumber);
 #if XFS_BIG_INUMS
                p.ino += mp->m_inoadd;
 #endif
@@ -626,7 +635,7 @@ xfs_dir2_block_lookup(
        /*
         * Fill in inode number, release the block.
         */
-       args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
+       args->inumber = be64_to_cpu(dep->inumber);
        xfs_da_brelse(args->trans, bp);
        return XFS_ERROR(EEXIST);
 }
@@ -844,11 +853,11 @@ xfs_dir2_block_replace(
         */
        dep = (xfs_dir2_data_entry_t *)
              ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
-       ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber);
+       ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
        /*
         * Change the inode number to the new value.
         */
-       INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+       dep->inumber = cpu_to_be64(args->inumber);
        xfs_dir2_data_log_entry(args->trans, bp, dep);
        xfs_dir2_data_check(dp, bp);
        xfs_da_buf_done(bp);
@@ -1130,7 +1139,7 @@ xfs_dir2_sf_to_block(
         */
        dep = (xfs_dir2_data_entry_t *)
              ((char *)block + XFS_DIR2_DATA_DOT_OFFSET);
-       INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino);
+       dep->inumber = cpu_to_be64(dp->i_ino);
        dep->namelen = 1;
        dep->name[0] = '.';
        tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
@@ -1144,7 +1153,7 @@ xfs_dir2_sf_to_block(
         */
        dep = (xfs_dir2_data_entry_t *)
                ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);
-       INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
+       dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
        dep->namelen = 2;
        dep->name[0] = dep->name[1] = '.';
        tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
@@ -1193,7 +1202,7 @@ xfs_dir2_sf_to_block(
                 * Copy a real entry.
                 */
                dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);
-               INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp,
+               dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp,
                                XFS_DIR2_SF_INUMBERP(sfep)));
                dep->namelen = sfep->namelen;
                memcpy(dep->name, sfep->name, dep->namelen);
index bb3d03ff002ba49c702d81926338893ff3208c5d..f7c799217072066518a560965c907cc8f428ef35 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_dir_leaf.h"
 #include "xfs_dir2_data.h"
 #include "xfs_dir2_leaf.h"
 #include "xfs_dir2_block.h"
@@ -133,7 +130,7 @@ xfs_dir2_data_check(
                 */
                dep = (xfs_dir2_data_entry_t *)p;
                ASSERT(dep->namelen != 0);
-               ASSERT(xfs_dir_ino_validate(mp, INT_GET(dep->inumber, ARCH_CONVERT)) == 0);
+               ASSERT(xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)) == 0);
                ASSERT(be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)) ==
                       (char *)dep - (char *)d);
                count++;
index 0847cbb53e17b7faeb7545639d64e717a4e30463..a6ae2d21c40abf9d3ca6f7fa0402b084a114898a 100644 (file)
@@ -85,11 +85,11 @@ typedef struct xfs_dir2_data_hdr {
  * Tag appears as the last 2 bytes.
  */
 typedef struct xfs_dir2_data_entry {
-       xfs_ino_t               inumber;        /* inode number */
-       __uint8_t               namelen;        /* name length */
-       __uint8_t               name[1];        /* name bytes, no null */
+       __be64                  inumber;        /* inode number */
+       __u8                    namelen;        /* name length */
+       __u8                    name[1];        /* name bytes, no null */
                                                /* variable offset */
-       xfs_dir2_data_off_t     tag;            /* starting offset of us */
+       __be16                  tag;            /* starting offset of us */
 } xfs_dir2_data_entry_t;
 
 /*
index 0f5e2f2ce6ec468afb5e545456b9915908ac482c..b1cf1fbf423d346aa1064d412337b1c05d4dd962 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_attr_sf.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
@@ -407,7 +405,7 @@ xfs_dir2_leaf_addname(
         * Initialize our new entry (at last).
         */
        dep = (xfs_dir2_data_entry_t *)dup;
-       INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+       dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, dep->namelen);
        tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
@@ -884,7 +882,7 @@ xfs_dir2_leaf_getdents(
                                        XFS_DIR2_BYTE_TO_DA(mp,
                                                XFS_DIR2_LEAF_OFFSET) - map_off,
                                        XFS_BMAPI_METADATA, NULL, 0,
-                                       &map[map_valid], &nmap, NULL);
+                                       &map[map_valid], &nmap, NULL, NULL);
                                /*
                                 * Don't know if we should ignore this or
                                 * try to return an error.
@@ -1098,7 +1096,7 @@ xfs_dir2_leaf_getdents(
 
                p->cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff + length);
 
-               p->ino = INT_GET(dep->inumber, ARCH_CONVERT);
+               p->ino = be64_to_cpu(dep->inumber);
 #if XFS_BIG_INUMS
                p->ino += mp->m_inoadd;
 #endif
@@ -1319,7 +1317,7 @@ xfs_dir2_leaf_lookup(
        /*
         * Return the found inode number.
         */
-       args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
+       args->inumber = be64_to_cpu(dep->inumber);
        xfs_da_brelse(tp, dbp);
        xfs_da_brelse(tp, lbp);
        return XFS_ERROR(EEXIST);
@@ -1606,11 +1604,11 @@ xfs_dir2_leaf_replace(
        dep = (xfs_dir2_data_entry_t *)
              ((char *)dbp->data +
               XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address)));
-       ASSERT(args->inumber != INT_GET(dep->inumber, ARCH_CONVERT));
+       ASSERT(args->inumber != be64_to_cpu(dep->inumber));
        /*
         * Put the new inode number in, log it.
         */
-       INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+       dep->inumber = cpu_to_be64(args->inumber);
        tp = args->trans;
        xfs_dir2_data_log_entry(tp, dbp, dep);
        xfs_da_buf_done(dbp);
index ac511ab9c52de4ddfd521fdd25523ca30e7e811e..9ca71719b683b041ff67795d316f55c2b96008d7 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -505,7 +503,6 @@ xfs_dir2_leafn_lookup_int(
                                                        XFS_DATA_FORK))) {
                                                return error;
                                        }
-                                       curfdb = newfdb;
                                        free = curbp->data;
                                        ASSERT(be32_to_cpu(free->hdr.magic) ==
                                               XFS_DIR2_FREE_MAGIC);
@@ -527,8 +524,11 @@ xfs_dir2_leafn_lookup_int(
                                if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) {
                                        XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int",
                                                         XFS_ERRLEVEL_LOW, mp);
+                                       if (curfdb != newfdb)
+                                               xfs_da_brelse(tp, curbp);
                                        return XFS_ERROR(EFSCORRUPTED);
                                }
+                               curfdb = newfdb;
                                if (be16_to_cpu(free->bests[fi]) >= length) {
                                        *indexp = index;
                                        state->extravalid = 1;
@@ -580,7 +580,7 @@ xfs_dir2_leafn_lookup_int(
                        if (dep->namelen == args->namelen &&
                            dep->name[0] == args->name[0] &&
                            memcmp(dep->name, args->name, args->namelen) == 0) {
-                               args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
+                               args->inumber = be64_to_cpu(dep->inumber);
                                *indexp = index;
                                state->extravalid = 1;
                                state->extrablk.bp = curbp;
@@ -970,7 +970,7 @@ xfs_dir2_leafn_remove(
                        /*
                         * One less used entry in the free table.
                         */
-                       free->hdr.nused = cpu_to_be32(-1);
+                       be32_add(&free->hdr.nused, -1);
                        xfs_dir2_free_log_header(tp, fbp);
                        /*
                         * If this was the last entry in the table, we can
@@ -1695,7 +1695,7 @@ xfs_dir2_node_addname_int(
         * Fill in the new entry and log it.
         */
        dep = (xfs_dir2_data_entry_t *)dup;
-       INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
+       dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, dep->namelen);
        tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
@@ -1905,11 +1905,11 @@ xfs_dir2_node_replace(
                dep = (xfs_dir2_data_entry_t *)
                      ((char *)data +
                       XFS_DIR2_DATAPTR_TO_OFF(state->mp, be32_to_cpu(lep->address)));
-               ASSERT(inum != INT_GET(dep->inumber, ARCH_CONVERT));
+               ASSERT(inum != be64_to_cpu(dep->inumber));
                /*
                 * Fill in the new inode number and log the entry.
                 */
-               INT_SET(dep->inumber, ARCH_CONVERT, inum);
+               dep->inumber = cpu_to_be64(inum);
                xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep);
                rval = 0;
        }
index d98a41d1fe63f3cead5051154660115b9703d80e..0cd77b17bf92d8c2283e26420efe8a4528bc6679 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
-#include "xfs_dir_leaf.h"
 #include "xfs_error.h"
 #include "xfs_dir2_data.h"
 #include "xfs_dir2_leaf.h"
@@ -117,13 +114,13 @@ xfs_dir2_block_sfsize(
                        dep->name[0] == '.' && dep->name[1] == '.';
 #if XFS_BIG_INUMS
                if (!isdot)
-                       i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM;
+                       i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
 #endif
                if (!isdot && !isdotdot) {
                        count++;
                        namelen += dep->namelen;
                } else if (isdotdot)
-                       parent = INT_GET(dep->inumber, ARCH_CONVERT);
+                       parent = be64_to_cpu(dep->inumber);
                /*
                 * Calculate the new size, see if we should give up yet.
                 */
@@ -229,13 +226,13 @@ xfs_dir2_block_to_sf(
                 * Skip .
                 */
                if (dep->namelen == 1 && dep->name[0] == '.')
-                       ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == dp->i_ino);
+                       ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
                /*
                 * Skip .., but make sure the inode number is right.
                 */
                else if (dep->namelen == 2 &&
                         dep->name[0] == '.' && dep->name[1] == '.')
-                       ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) ==
+                       ASSERT(be64_to_cpu(dep->inumber) ==
                               XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
                /*
                 * Normal entry, copy it into shortform.
@@ -246,7 +243,7 @@ xfs_dir2_block_to_sf(
                                (xfs_dir2_data_aoff_t)
                                ((char *)dep - (char *)block));
                        memcpy(sfep->name, dep->name, dep->namelen);
-                       temp=INT_GET(dep->inumber, ARCH_CONVERT);
+                       temp = be64_to_cpu(dep->inumber);
                        XFS_DIR2_SF_PUT_INUMBER(sfp, &temp,
                                XFS_DIR2_SF_INUMBERP(sfep));
                        sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
index c626943b41123e04bdeb48c4fa05f0b2f1d1e74f..f3fb2ffd6f5c7ca0c897257f05db9acd5d5a8a14 100644 (file)
 #include "xfs_fs.h"
 #include "xfs_types.h"
 #include "xfs_inum.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
diff --git a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c
deleted file mode 100644 (file)
index 6d71186..0000000
+++ /dev/null
@@ -1,2213 +0,0 @@
-/*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_dir.h"
-#include "xfs_dir2.h"
-#include "xfs_dmapi.h"
-#include "xfs_mount.h"
-#include "xfs_da_btree.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
-#include "xfs_dir2_sf.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_alloc.h"
-#include "xfs_btree.h"
-#include "xfs_bmap.h"
-#include "xfs_dir_leaf.h"
-#include "xfs_error.h"
-
-/*
- * xfs_dir_leaf.c
- *
- * Routines to implement leaf blocks of directories as Btrees of hashed names.
- */
-
-/*========================================================================
- * Function prototypes for the kernel.
- *========================================================================*/
-
-/*
- * Routines used for growing the Btree.
- */
-STATIC void xfs_dir_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args,
-                                             int insertion_index,
-                                             int freemap_index);
-STATIC int xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer,
-                                           int musthave, int justcheck);
-STATIC void xfs_dir_leaf_rebalance(xfs_da_state_t *state,
-                                                 xfs_da_state_blk_t *blk1,
-                                                 xfs_da_state_blk_t *blk2);
-STATIC int xfs_dir_leaf_figure_balance(xfs_da_state_t *state,
-                                         xfs_da_state_blk_t *leaf_blk_1,
-                                         xfs_da_state_blk_t *leaf_blk_2,
-                                         int *number_entries_in_blk1,
-                                         int *number_namebytes_in_blk1);
-
-STATIC int xfs_dir_leaf_create(struct xfs_da_args *args,
-                               xfs_dablk_t which_block,
-                               struct xfs_dabuf **bpp);
-
-/*
- * Utility routines.
- */
-STATIC void xfs_dir_leaf_moveents(xfs_dir_leafblock_t *src_leaf,
-                                             int src_start,
-                                             xfs_dir_leafblock_t *dst_leaf,
-                                             int dst_start, int move_count,
-                                             xfs_mount_t *mp);
-
-
-/*========================================================================
- * External routines when dirsize < XFS_IFORK_DSIZE(dp).
- *========================================================================*/
-
-
-/*
- * Validate a given inode number.
- */
-int
-xfs_dir_ino_validate(xfs_mount_t *mp, xfs_ino_t ino)
-{
-       xfs_agblock_t   agblkno;
-       xfs_agino_t     agino;
-       xfs_agnumber_t  agno;
-       int             ino_ok;
-       int             ioff;
-
-       agno = XFS_INO_TO_AGNO(mp, ino);
-       agblkno = XFS_INO_TO_AGBNO(mp, ino);
-       ioff = XFS_INO_TO_OFFSET(mp, ino);
-       agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff);
-       ino_ok =
-               agno < mp->m_sb.sb_agcount &&
-               agblkno < mp->m_sb.sb_agblocks &&
-               agblkno != 0 &&
-               ioff < (1 << mp->m_sb.sb_inopblog) &&
-               XFS_AGINO_TO_INO(mp, agno, agino) == ino;
-       if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
-                       XFS_RANDOM_DIR_INO_VALIDATE))) {
-               xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
-                               (unsigned long long) ino);
-               XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-       return 0;
-}
-
-/*
- * Create the initial contents of a shortform directory.
- */
-int
-xfs_dir_shortform_create(xfs_da_args_t *args, xfs_ino_t parent)
-{
-       xfs_dir_sf_hdr_t *hdr;
-       xfs_inode_t *dp;
-
-       dp = args->dp;
-       ASSERT(dp != NULL);
-       ASSERT(dp->i_d.di_size == 0);
-       if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) {
-               dp->i_df.if_flags &= ~XFS_IFEXTENTS;    /* just in case */
-               dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
-               xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
-               dp->i_df.if_flags |= XFS_IFINLINE;
-       }
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       ASSERT(dp->i_df.if_bytes == 0);
-       xfs_idata_realloc(dp, sizeof(*hdr), XFS_DATA_FORK);
-       hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data;
-       XFS_DIR_SF_PUT_DIRINO(&parent, &hdr->parent);
-
-       hdr->count = 0;
-       dp->i_d.di_size = sizeof(*hdr);
-       xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
-       return 0;
-}
-
-/*
- * Add a name to the shortform directory structure.
- * Overflow from the inode has already been checked for.
- */
-int
-xfs_dir_shortform_addname(xfs_da_args_t *args)
-{
-       xfs_dir_shortform_t *sf;
-       xfs_dir_sf_entry_t *sfe;
-       int i, offset, size;
-       xfs_inode_t *dp;
-
-       dp = args->dp;
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Catch the case where the conversion from shortform to leaf
-        * failed part way through.
-        */
-       if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return XFS_ERROR(EIO);
-       }
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
-       sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
-       sfe = &sf->list[0];
-       for (i = sf->hdr.count-1; i >= 0; i--) {
-               if (sfe->namelen == args->namelen &&
-                   args->name[0] == sfe->name[0] &&
-                   memcmp(args->name, sfe->name, args->namelen) == 0)
-                       return XFS_ERROR(EEXIST);
-               sfe = XFS_DIR_SF_NEXTENTRY(sfe);
-       }
-
-       offset = (int)((char *)sfe - (char *)sf);
-       size = XFS_DIR_SF_ENTSIZE_BYNAME(args->namelen);
-       xfs_idata_realloc(dp, size, XFS_DATA_FORK);
-       sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
-       sfe = (xfs_dir_sf_entry_t *)((char *)sf + offset);
-
-       XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber);
-       sfe->namelen = args->namelen;
-       memcpy(sfe->name, args->name, sfe->namelen);
-       sf->hdr.count++;
-
-       dp->i_d.di_size += size;
-       xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
-
-       return 0;
-}
-
-/*
- * Remove a name from the shortform directory structure.
- */
-int
-xfs_dir_shortform_removename(xfs_da_args_t *args)
-{
-       xfs_dir_shortform_t *sf;
-       xfs_dir_sf_entry_t *sfe;
-       int base, size = 0, i;
-       xfs_inode_t *dp;
-
-       dp = args->dp;
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Catch the case where the conversion from shortform to leaf
-        * failed part way through.
-        */
-       if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return XFS_ERROR(EIO);
-       }
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
-       base = sizeof(xfs_dir_sf_hdr_t);
-       sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
-       sfe = &sf->list[0];
-       for (i = sf->hdr.count-1; i >= 0; i--) {
-               size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe);
-               if (sfe->namelen == args->namelen &&
-                   sfe->name[0] == args->name[0] &&
-                   memcmp(sfe->name, args->name, args->namelen) == 0)
-                       break;
-               base += size;
-               sfe = XFS_DIR_SF_NEXTENTRY(sfe);
-       }
-       if (i < 0) {
-               ASSERT(args->oknoent);
-               return XFS_ERROR(ENOENT);
-       }
-
-       if ((base + size) != dp->i_d.di_size) {
-               memmove(&((char *)sf)[base], &((char *)sf)[base+size],
-                                             dp->i_d.di_size - (base+size));
-       }
-       sf->hdr.count--;
-
-       xfs_idata_realloc(dp, -size, XFS_DATA_FORK);
-       dp->i_d.di_size -= size;
-       xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
-
-       return 0;
-}
-
-/*
- * Look up a name in a shortform directory structure.
- */
-int
-xfs_dir_shortform_lookup(xfs_da_args_t *args)
-{
-       xfs_dir_shortform_t *sf;
-       xfs_dir_sf_entry_t *sfe;
-       int i;
-       xfs_inode_t *dp;
-
-       dp = args->dp;
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Catch the case where the conversion from shortform to leaf
-        * failed part way through.
-        */
-       if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return XFS_ERROR(EIO);
-       }
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
-       sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
-       if (args->namelen == 2 &&
-           args->name[0] == '.' && args->name[1] == '.') {
-               XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &args->inumber);
-               return(XFS_ERROR(EEXIST));
-       }
-       if (args->namelen == 1 && args->name[0] == '.') {
-               args->inumber = dp->i_ino;
-               return(XFS_ERROR(EEXIST));
-       }
-       sfe = &sf->list[0];
-       for (i = sf->hdr.count-1; i >= 0; i--) {
-               if (sfe->namelen == args->namelen &&
-                   sfe->name[0] == args->name[0] &&
-                   memcmp(args->name, sfe->name, args->namelen) == 0) {
-                       XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args->inumber);
-                       return(XFS_ERROR(EEXIST));
-               }
-               sfe = XFS_DIR_SF_NEXTENTRY(sfe);
-       }
-       ASSERT(args->oknoent);
-       return(XFS_ERROR(ENOENT));
-}
-
-/*
- * Convert from using the shortform to the leaf.
- */
-int
-xfs_dir_shortform_to_leaf(xfs_da_args_t *iargs)
-{
-       xfs_inode_t *dp;
-       xfs_dir_shortform_t *sf;
-       xfs_dir_sf_entry_t *sfe;
-       xfs_da_args_t args;
-       xfs_ino_t inumber;
-       char *tmpbuffer;
-       int retval, i, size;
-       xfs_dablk_t blkno;
-       xfs_dabuf_t *bp;
-
-       dp = iargs->dp;
-       /*
-        * Catch the case where the conversion from shortform to leaf
-        * failed part way through.
-        */
-       if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return XFS_ERROR(EIO);
-       }
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
-       size = dp->i_df.if_bytes;
-       tmpbuffer = kmem_alloc(size, KM_SLEEP);
-       ASSERT(tmpbuffer != NULL);
-
-       memcpy(tmpbuffer, dp->i_df.if_u1.if_data, size);
-
-       sf = (xfs_dir_shortform_t *)tmpbuffer;
-       XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &inumber);
-
-       xfs_idata_realloc(dp, -size, XFS_DATA_FORK);
-       dp->i_d.di_size = 0;
-       xfs_trans_log_inode(iargs->trans, dp, XFS_ILOG_CORE);
-       retval = xfs_da_grow_inode(iargs, &blkno);
-       if (retval)
-               goto out;
-
-       ASSERT(blkno == 0);
-       retval = xfs_dir_leaf_create(iargs, blkno, &bp);
-       if (retval)
-               goto out;
-       xfs_da_buf_done(bp);
-
-       args.name = ".";
-       args.namelen = 1;
-       args.hashval = xfs_dir_hash_dot;
-       args.inumber = dp->i_ino;
-       args.dp = dp;
-       args.firstblock = iargs->firstblock;
-       args.flist = iargs->flist;
-       args.total = iargs->total;
-       args.whichfork = XFS_DATA_FORK;
-       args.trans = iargs->trans;
-       args.justcheck = 0;
-       args.addname = args.oknoent = 1;
-       retval = xfs_dir_leaf_addname(&args);
-       if (retval)
-               goto out;
-
-       args.name = "..";
-       args.namelen = 2;
-       args.hashval = xfs_dir_hash_dotdot;
-       args.inumber = inumber;
-       retval = xfs_dir_leaf_addname(&args);
-       if (retval)
-               goto out;
-
-       sfe = &sf->list[0];
-       for (i = 0; i < sf->hdr.count; i++) {
-               args.name = (char *)(sfe->name);
-               args.namelen = sfe->namelen;
-               args.hashval = xfs_da_hashname((char *)(sfe->name),
-                                              sfe->namelen);
-               XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args.inumber);
-               retval = xfs_dir_leaf_addname(&args);
-               if (retval)
-                       goto out;
-               sfe = XFS_DIR_SF_NEXTENTRY(sfe);
-       }
-       retval = 0;
-
-out:
-       kmem_free(tmpbuffer, size);
-       return retval;
-}
-
-STATIC int
-xfs_dir_shortform_compare(const void *a, const void *b)
-{
-       xfs_dir_sf_sort_t *sa, *sb;
-
-       sa = (xfs_dir_sf_sort_t *)a;
-       sb = (xfs_dir_sf_sort_t *)b;
-       if (sa->hash < sb->hash)
-               return -1;
-       else if (sa->hash > sb->hash)
-               return 1;
-       else
-               return sa->entno - sb->entno;
-}
-
-/*
- * Copy out directory entries for getdents(), for shortform directories.
- */
-/*ARGSUSED*/
-int
-xfs_dir_shortform_getdents(xfs_inode_t *dp, uio_t *uio, int *eofp,
-                                      xfs_dirent_t *dbp, xfs_dir_put_t put)
-{
-       xfs_dir_shortform_t *sf;
-       xfs_dir_sf_entry_t *sfe;
-       int retval, i, sbsize, nsbuf, lastresid=0, want_entno;
-       xfs_mount_t *mp;
-       xfs_dahash_t cookhash, hash;
-       xfs_dir_put_args_t p;
-       xfs_dir_sf_sort_t *sbuf, *sbp;
-
-       mp = dp->i_mount;
-       sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
-       cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset);
-       want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset);
-       nsbuf = sf->hdr.count + 2;
-       sbsize = (nsbuf + 1) * sizeof(*sbuf);
-       sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP);
-
-       xfs_dir_trace_g_du("sf: start", dp, uio);
-
-       /*
-        * Collect all the entries into the buffer.
-        * Entry 0 is .
-        */
-       sbp->entno = 0;
-       sbp->seqno = 0;
-       sbp->hash = xfs_dir_hash_dot;
-       sbp->ino = dp->i_ino;
-       sbp->name = ".";
-       sbp->namelen = 1;
-       sbp++;
-
-       /*
-        * Entry 1 is ..
-        */
-       sbp->entno = 1;
-       sbp->seqno = 0;
-       sbp->hash = xfs_dir_hash_dotdot;
-       sbp->ino = XFS_GET_DIR_INO8(sf->hdr.parent);
-       sbp->name = "..";
-       sbp->namelen = 2;
-       sbp++;
-
-       /*
-        * Scan the directory data for the rest of the entries.
-        */
-       for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
-
-               if (unlikely(
-                   ((char *)sfe < (char *)sf) ||
-                   ((char *)sfe >= ((char *)sf + dp->i_df.if_bytes)))) {
-                       xfs_dir_trace_g_du("sf: corrupted", dp, uio);
-                       XFS_CORRUPTION_ERROR("xfs_dir_shortform_getdents",
-                                            XFS_ERRLEVEL_LOW, mp, sfe);
-                       kmem_free(sbuf, sbsize);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-
-               sbp->entno = i + 2;
-               sbp->seqno = 0;
-               sbp->hash = xfs_da_hashname((char *)sfe->name, sfe->namelen);
-               sbp->ino = XFS_GET_DIR_INO8(sfe->inumber);
-               sbp->name = (char *)sfe->name;
-               sbp->namelen = sfe->namelen;
-               sfe = XFS_DIR_SF_NEXTENTRY(sfe);
-               sbp++;
-       }
-
-       /*
-        * Sort the entries on hash then entno.
-        */
-       xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_dir_shortform_compare);
-       /*
-        * Stuff in last entry.
-        */
-       sbp->entno = nsbuf;
-       sbp->hash = XFS_DA_MAXHASH;
-       sbp->seqno = 0;
-       /*
-        * Figure out the sequence numbers in case there's a hash duplicate.
-        */
-       for (hash = sbuf->hash, sbp = sbuf + 1;
-                               sbp < &sbuf[nsbuf + 1]; sbp++) {
-               if (sbp->hash == hash)
-                       sbp->seqno = sbp[-1].seqno + 1;
-               else
-                       hash = sbp->hash;
-       }
-
-       /*
-        * Set up put routine.
-        */
-       p.dbp = dbp;
-       p.put = put;
-       p.uio = uio;
-
-       /*
-        * Find our place.
-        */
-       for (sbp = sbuf; sbp < &sbuf[nsbuf + 1]; sbp++) {
-               if (sbp->hash > cookhash ||
-                   (sbp->hash == cookhash && sbp->seqno >= want_entno))
-                       break;
-       }
-
-       /*
-        * Did we fail to find anything?  We stop at the last entry,
-        * the one we put maxhash into.
-        */
-       if (sbp == &sbuf[nsbuf]) {
-               kmem_free(sbuf, sbsize);
-               xfs_dir_trace_g_du("sf: hash beyond end", dp, uio);
-               uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH);
-               *eofp = 1;
-               return 0;
-       }
-
-       /*
-        * Loop putting entries into the user buffer.
-        */
-       while (sbp < &sbuf[nsbuf]) {
-               /*
-                * Save the first resid in a run of equal-hashval entries
-                * so that we can back them out if they don't all fit.
-                */
-               if (sbp->seqno == 0 || sbp == sbuf)
-                       lastresid = uio->uio_resid;
-               XFS_PUT_COOKIE(p.cook, mp, 0, sbp[1].seqno, sbp[1].hash);
-               p.ino = sbp->ino;
-#if XFS_BIG_INUMS
-               p.ino += mp->m_inoadd;
-#endif
-               p.name = sbp->name;
-               p.namelen = sbp->namelen;
-               retval = p.put(&p);
-               if (!p.done) {
-                       uio->uio_offset =
-                               XFS_DA_MAKE_COOKIE(mp, 0, 0, sbp->hash);
-                       kmem_free(sbuf, sbsize);
-                       uio->uio_resid = lastresid;
-                       xfs_dir_trace_g_du("sf: E-O-B", dp, uio);
-                       return retval;
-               }
-               sbp++;
-       }
-       kmem_free(sbuf, sbsize);
-       uio->uio_offset = p.cook.o;
-       *eofp = 1;
-       xfs_dir_trace_g_du("sf: E-O-F", dp, uio);
-       return 0;
-}
-
-/*
- * Look up a name in a shortform directory structure, replace the inode number.
- */
-int
-xfs_dir_shortform_replace(xfs_da_args_t *args)
-{
-       xfs_dir_shortform_t *sf;
-       xfs_dir_sf_entry_t *sfe;
-       xfs_inode_t *dp;
-       int i;
-
-       dp = args->dp;
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Catch the case where the conversion from shortform to leaf
-        * failed part way through.
-        */
-       if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
-               return XFS_ERROR(EIO);
-       }
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
-       sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data;
-       if (args->namelen == 2 &&
-           args->name[0] == '.' && args->name[1] == '.') {
-               /* XXX - replace assert? */
-               XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sf->hdr.parent);
-               xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
-               return 0;
-       }
-       ASSERT(args->namelen != 1 || args->name[0] != '.');
-       sfe = &sf->list[0];
-       for (i = sf->hdr.count-1; i >= 0; i--) {
-               if (sfe->namelen == args->namelen &&
-                   sfe->name[0] == args->name[0] &&
-                   memcmp(args->name, sfe->name, args->namelen) == 0) {
-                       ASSERT(memcmp((char *)&args->inumber,
-                               (char *)&sfe->inumber, sizeof(xfs_ino_t)));
-                       XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber);
-                       xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
-                       return 0;
-               }
-               sfe = XFS_DIR_SF_NEXTENTRY(sfe);
-       }
-       ASSERT(args->oknoent);
-       return XFS_ERROR(ENOENT);
-}
-
-/*
- * Convert a leaf directory to shortform structure
- */
-int
-xfs_dir_leaf_to_shortform(xfs_da_args_t *iargs)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_hdr_t *hdr;
-       xfs_dir_leaf_entry_t *entry;
-       xfs_dir_leaf_name_t *namest;
-       xfs_da_args_t args;
-       xfs_inode_t *dp;
-       xfs_ino_t parent = 0;
-       char *tmpbuffer;
-       int retval, i;
-       xfs_dabuf_t *bp;
-
-       dp = iargs->dp;
-       tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);
-       ASSERT(tmpbuffer != NULL);
-
-       retval = xfs_da_read_buf(iargs->trans, iargs->dp, 0, -1, &bp,
-                                              XFS_DATA_FORK);
-       if (retval)
-               goto out;
-       ASSERT(bp != NULL);
-       memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
-       leaf = (xfs_dir_leafblock_t *)tmpbuffer;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
-
-       /*
-        * Find and special case the parent inode number
-        */
-       hdr = &leaf->hdr;
-       entry = &leaf->entries[0];
-       for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) {
-               namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-               if ((entry->namelen == 2) &&
-                   (namest->name[0] == '.') &&
-                   (namest->name[1] == '.')) {
-                       XFS_DIR_SF_GET_DIRINO(&namest->inumber, &parent);
-                       entry->nameidx = 0;
-               } else if ((entry->namelen == 1) && (namest->name[0] == '.')) {
-                       entry->nameidx = 0;
-               }
-       }
-       retval = xfs_da_shrink_inode(iargs, 0, bp);
-       if (retval)
-               goto out;
-       retval = xfs_dir_shortform_create(iargs, parent);
-       if (retval)
-               goto out;
-
-       /*
-        * Copy the rest of the filenames
-        */
-       entry = &leaf->entries[0];
-       args.dp = dp;
-       args.firstblock = iargs->firstblock;
-       args.flist = iargs->flist;
-       args.total = iargs->total;
-       args.whichfork = XFS_DATA_FORK;
-       args.trans = iargs->trans;
-       args.justcheck = 0;
-       args.addname = args.oknoent = 1;
-       for (i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) {
-               if (!entry->nameidx)
-                       continue;
-               namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-               args.name = (char *)(namest->name);
-               args.namelen = entry->namelen;
-               args.hashval = INT_GET(entry->hashval, ARCH_CONVERT);
-               XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args.inumber);
-               xfs_dir_shortform_addname(&args);
-       }
-
-out:
-       kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount));
-       return retval;
-}
-
-/*
- * Convert from using a single leaf to a root node and a leaf.
- */
-int
-xfs_dir_leaf_to_node(xfs_da_args_t *args)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_da_intnode_t *node;
-       xfs_inode_t *dp;
-       xfs_dabuf_t *bp1, *bp2;
-       xfs_dablk_t blkno;
-       int retval;
-
-       dp = args->dp;
-       retval = xfs_da_grow_inode(args, &blkno);
-       ASSERT(blkno == 1);
-       if (retval)
-               return retval;
-       retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1,
-                                             XFS_DATA_FORK);
-       if (retval)
-               return retval;
-       ASSERT(bp1 != NULL);
-       retval = xfs_da_get_buf(args->trans, args->dp, 1, -1, &bp2,
-                                            XFS_DATA_FORK);
-       if (retval) {
-               xfs_da_buf_done(bp1);
-               return retval;
-       }
-       ASSERT(bp2 != NULL);
-       memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
-       xfs_da_buf_done(bp1);
-       xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
-
-       /*
-        * Set up the new root node.
-        */
-       retval = xfs_da_node_create(args, 0, 1, &bp1, XFS_DATA_FORK);
-       if (retval) {
-               xfs_da_buf_done(bp2);
-               return retval;
-       }
-       node = bp1->data;
-       leaf = bp2->data;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       node->btree[0].hashval = cpu_to_be32(
-               INT_GET(leaf->entries[
-                       INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
-       xfs_da_buf_done(bp2);
-       node->btree[0].before = cpu_to_be32(blkno);
-       node->hdr.count = cpu_to_be16(1);
-       xfs_da_log_buf(args->trans, bp1,
-               XFS_DA_LOGRANGE(node, &node->btree[0], sizeof(node->btree[0])));
-       xfs_da_buf_done(bp1);
-
-       return retval;
-}
-
-
-/*========================================================================
- * Routines used for growing the Btree.
- *========================================================================*/
-
-/*
- * Create the initial contents of a leaf directory
- * or a leaf in a node directory.
- */
-STATIC int
-xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_hdr_t *hdr;
-       xfs_inode_t *dp;
-       xfs_dabuf_t *bp;
-       int retval;
-
-       dp = args->dp;
-       ASSERT(dp != NULL);
-       retval = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp, XFS_DATA_FORK);
-       if (retval)
-               return retval;
-       ASSERT(bp != NULL);
-       leaf = bp->data;
-       memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
-       hdr = &leaf->hdr;
-       hdr->info.magic = cpu_to_be16(XFS_DIR_LEAF_MAGIC);
-       INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
-       if (!hdr->firstused)
-               INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - 1);
-       INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t));
-       INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT));
-
-       xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);
-
-       *bpp = bp;
-       return 0;
-}
-
-/*
- * Split the leaf node, rebalance, then add the new entry.
- */
-int
-xfs_dir_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
-                                 xfs_da_state_blk_t *newblk)
-{
-       xfs_dablk_t blkno;
-       xfs_da_args_t *args;
-       int error;
-
-       /*
-        * Allocate space for a new leaf node.
-        */
-       args = state->args;
-       ASSERT(args != NULL);
-       ASSERT(oldblk->magic == XFS_DIR_LEAF_MAGIC);
-       error = xfs_da_grow_inode(args, &blkno);
-       if (error)
-               return error;
-       error = xfs_dir_leaf_create(args, blkno, &newblk->bp);
-       if (error)
-               return error;
-       newblk->blkno = blkno;
-       newblk->magic = XFS_DIR_LEAF_MAGIC;
-
-       /*
-        * Rebalance the entries across the two leaves.
-        */
-       xfs_dir_leaf_rebalance(state, oldblk, newblk);
-       error = xfs_da_blk_link(state, oldblk, newblk);
-       if (error)
-               return error;
-
-       /*
-        * Insert the new entry in the correct block.
-        */
-       if (state->inleaf) {
-               error = xfs_dir_leaf_add(oldblk->bp, args, oldblk->index);
-       } else {
-               error = xfs_dir_leaf_add(newblk->bp, args, newblk->index);
-       }
-
-       /*
-        * Update last hashval in each block since we added the name.
-        */
-       oldblk->hashval = xfs_dir_leaf_lasthash(oldblk->bp, NULL);
-       newblk->hashval = xfs_dir_leaf_lasthash(newblk->bp, NULL);
-       return error;
-}
-
-/*
- * Add a name to the leaf directory structure.
- *
- * Must take into account fragmented leaves and leaves where spacemap has
- * lost some freespace information (ie: holes).
- */
-int
-xfs_dir_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_hdr_t *hdr;
-       xfs_dir_leaf_map_t *map;
-       int tablesize, entsize, sum, i, tmp, error;
-
-       leaf = bp->data;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       ASSERT((index >= 0) && (index <= INT_GET(leaf->hdr.count, ARCH_CONVERT)));
-       hdr = &leaf->hdr;
-       entsize = XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen);
-
-       /*
-        * Search through freemap for first-fit on new name length.
-        * (may need to figure in size of entry struct too)
-        */
-       tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) * (uint)sizeof(xfs_dir_leaf_entry_t)
-                       + (uint)sizeof(xfs_dir_leaf_hdr_t);
-       map = &hdr->freemap[XFS_DIR_LEAF_MAPSIZE-1];
-       for (sum = 0, i = XFS_DIR_LEAF_MAPSIZE-1; i >= 0; map--, i--) {
-               if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) {
-                       sum += INT_GET(map->size, ARCH_CONVERT);
-                       continue;
-               }
-               if (!map->size)
-                       continue;       /* no space in this map */
-               tmp = entsize;
-               if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
-                       tmp += (uint)sizeof(xfs_dir_leaf_entry_t);
-               if (INT_GET(map->size, ARCH_CONVERT) >= tmp) {
-                       if (!args->justcheck)
-                               xfs_dir_leaf_add_work(bp, args, index, i);
-                       return 0;
-               }
-               sum += INT_GET(map->size, ARCH_CONVERT);
-       }
-
-       /*
-        * If there are no holes in the address space of the block,
-        * and we don't have enough freespace, then compaction will do us
-        * no good and we should just give up.
-        */
-       if (!hdr->holes && (sum < entsize))
-               return XFS_ERROR(ENOSPC);
-
-       /*
-        * Compact the entries to coalesce free space.
-        * Pass the justcheck flag so the checking pass can return
-        * an error, without changing anything, if it won't fit.
-        */
-       error = xfs_dir_leaf_compact(args->trans, bp,
-                       args->total == 0 ?
-                               entsize +
-                               (uint)sizeof(xfs_dir_leaf_entry_t) : 0,
-                       args->justcheck);
-       if (error)
-               return error;
-       /*
-        * After compaction, the block is guaranteed to have only one
-        * free region, in freemap[0].  If it is not big enough, give up.
-        */
-       if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) <
-           (entsize + (uint)sizeof(xfs_dir_leaf_entry_t)))
-               return XFS_ERROR(ENOSPC);
-
-       if (!args->justcheck)
-               xfs_dir_leaf_add_work(bp, args, index, 0);
-       return 0;
-}
-
-/*
- * Add a name to a leaf directory structure.
- */
-STATIC void
-xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index,
-                     int mapindex)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_hdr_t *hdr;
-       xfs_dir_leaf_entry_t *entry;
-       xfs_dir_leaf_name_t *namest;
-       xfs_dir_leaf_map_t *map;
-       /* REFERENCED */
-       xfs_mount_t *mp;
-       int tmp, i;
-
-       leaf = bp->data;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       hdr = &leaf->hdr;
-       ASSERT((mapindex >= 0) && (mapindex < XFS_DIR_LEAF_MAPSIZE));
-       ASSERT((index >= 0) && (index <= INT_GET(hdr->count, ARCH_CONVERT)));
-
-       /*
-        * Force open some space in the entry array and fill it in.
-        */
-       entry = &leaf->entries[index];
-       if (index < INT_GET(hdr->count, ARCH_CONVERT)) {
-               tmp  = INT_GET(hdr->count, ARCH_CONVERT) - index;
-               tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
-               memmove(entry + 1, entry, tmp);
-               xfs_da_log_buf(args->trans, bp,
-                   XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
-       }
-       INT_MOD(hdr->count, ARCH_CONVERT, +1);
-
-       /*
-        * Allocate space for the new string (at the end of the run).
-        */
-       map = &hdr->freemap[mapindex];
-       mp = args->trans->t_mountp;
-       ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
-       ASSERT(INT_GET(map->size, ARCH_CONVERT) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen));
-       ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
-       INT_MOD(map->size, ARCH_CONVERT, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)));
-       INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT));
-       INT_SET(entry->hashval, ARCH_CONVERT, args->hashval);
-       entry->namelen = args->namelen;
-       xfs_da_log_buf(args->trans, bp,
-           XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
-
-       /*
-        * Copy the string and inode number into the new space.
-        */
-       namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-       XFS_DIR_SF_PUT_DIRINO(&args->inumber, &namest->inumber);
-       memcpy(namest->name, args->name, args->namelen);
-       xfs_da_log_buf(args->trans, bp,
-           XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry)));
-
-       /*
-        * Update the control info for this leaf node
-        */
-       if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
-               INT_COPY(hdr->firstused, entry->nameidx, ARCH_CONVERT);
-       ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr)));
-       tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) * (uint)sizeof(xfs_dir_leaf_entry_t)
-                       + (uint)sizeof(xfs_dir_leaf_hdr_t);
-       map = &hdr->freemap[0];
-       for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) {
-               if (INT_GET(map->base, ARCH_CONVERT) == tmp) {
-                       INT_MOD(map->base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t));
-                       INT_MOD(map->size, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t)));
-               }
-       }
-       INT_MOD(hdr->namebytes, ARCH_CONVERT, args->namelen);
-       xfs_da_log_buf(args->trans, bp,
-               XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
-}
-
-/*
- * Garbage collect a leaf directory block by copying it to a new buffer.
- */
-STATIC int
-xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave,
-                    int justcheck)
-{
-       xfs_dir_leafblock_t *leaf_s, *leaf_d;
-       xfs_dir_leaf_hdr_t *hdr_s, *hdr_d;
-       xfs_mount_t *mp;
-       char *tmpbuffer;
-       char *tmpbuffer2=NULL;
-       int rval;
-       int lbsize;
-
-       mp = trans->t_mountp;
-       lbsize = XFS_LBSIZE(mp);
-       tmpbuffer = kmem_alloc(lbsize, KM_SLEEP);
-       ASSERT(tmpbuffer != NULL);
-       memcpy(tmpbuffer, bp->data, lbsize);
-
-       /*
-        * Make a second copy in case xfs_dir_leaf_moveents()
-        * below destroys the original.
-        */
-       if (musthave || justcheck) {
-               tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP);
-               memcpy(tmpbuffer2, bp->data, lbsize);
-       }
-       memset(bp->data, 0, lbsize);
-
-       /*
-        * Copy basic information
-        */
-       leaf_s = (xfs_dir_leafblock_t *)tmpbuffer;
-       leaf_d = bp->data;
-       hdr_s = &leaf_s->hdr;
-       hdr_d = &leaf_d->hdr;
-       hdr_d->info = hdr_s->info;      /* struct copy */
-       INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize);
-       if (!hdr_d->firstused)
-               INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize - 1);
-       hdr_d->namebytes = 0;
-       hdr_d->count = 0;
-       hdr_d->holes = 0;
-       INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t));
-       INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
-
-       /*
-        * Copy all entry's in the same (sorted) order,
-        * but allocate filenames packed and in sequence.
-        * This changes the source (leaf_s) as well.
-        */
-       xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp);
-
-       if (musthave && INT_GET(hdr_d->freemap[0].size, ARCH_CONVERT) < musthave)
-               rval = XFS_ERROR(ENOSPC);
-       else
-               rval = 0;
-
-       if (justcheck || rval == ENOSPC) {
-               ASSERT(tmpbuffer2);
-               memcpy(bp->data, tmpbuffer2, lbsize);
-       } else {
-               xfs_da_log_buf(trans, bp, 0, lbsize - 1);
-       }
-
-       kmem_free(tmpbuffer, lbsize);
-       if (musthave || justcheck)
-               kmem_free(tmpbuffer2, lbsize);
-       return rval;
-}
-
-/*
- * Redistribute the directory entries between two leaf nodes,
- * taking into account the size of the new entry.
- *
- * NOTE: if new block is empty, then it will get the upper half of old block.
- */
-STATIC void
-xfs_dir_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
-                                     xfs_da_state_blk_t *blk2)
-{
-       xfs_da_state_blk_t *tmp_blk;
-       xfs_dir_leafblock_t *leaf1, *leaf2;
-       xfs_dir_leaf_hdr_t *hdr1, *hdr2;
-       int count, totallen, max, space, swap;
-
-       /*
-        * Set up environment.
-        */
-       ASSERT(blk1->magic == XFS_DIR_LEAF_MAGIC);
-       ASSERT(blk2->magic == XFS_DIR_LEAF_MAGIC);
-       leaf1 = blk1->bp->data;
-       leaf2 = blk2->bp->data;
-       ASSERT(be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       ASSERT(be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-
-       /*
-        * Check ordering of blocks, reverse if it makes things simpler.
-        */
-       swap = 0;
-       if (xfs_dir_leaf_order(blk1->bp, blk2->bp)) {
-               tmp_blk = blk1;
-               blk1 = blk2;
-               blk2 = tmp_blk;
-               leaf1 = blk1->bp->data;
-               leaf2 = blk2->bp->data;
-               swap = 1;
-       }
-       hdr1 = &leaf1->hdr;
-       hdr2 = &leaf2->hdr;
-
-       /*
-        * Examine entries until we reduce the absolute difference in
-        * byte usage between the two blocks to a minimum.  Then get
-        * the direction to copy and the number of elements to move.
-        */
-       state->inleaf = xfs_dir_leaf_figure_balance(state, blk1, blk2,
-                                                          &count, &totallen);
-       if (swap)
-               state->inleaf = !state->inleaf;
-
-       /*
-        * Move any entries required from leaf to leaf:
-        */
-       if (count < INT_GET(hdr1->count, ARCH_CONVERT)) {
-               /*
-                * Figure the total bytes to be added to the destination leaf.
-                */
-               count = INT_GET(hdr1->count, ARCH_CONVERT) - count;     /* number entries being moved */
-               space  = INT_GET(hdr1->namebytes, ARCH_CONVERT) - totallen;
-               space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1);
-               space += count * (uint)sizeof(xfs_dir_leaf_entry_t);
-
-               /*
-                * leaf2 is the destination, compact it if it looks tight.
-                */
-               max  = INT_GET(hdr2->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t);
-               max -= INT_GET(hdr2->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t);
-               if (space > max) {
-                       xfs_dir_leaf_compact(state->args->trans, blk2->bp,
-                                                                0, 0);
-               }
-
-               /*
-                * Move high entries from leaf1 to low end of leaf2.
-                */
-               xfs_dir_leaf_moveents(leaf1, INT_GET(hdr1->count, ARCH_CONVERT) - count,
-                                            leaf2, 0, count, state->mp);
-
-               xfs_da_log_buf(state->args->trans, blk1->bp, 0,
-                                                  state->blocksize-1);
-               xfs_da_log_buf(state->args->trans, blk2->bp, 0,
-                                                  state->blocksize-1);
-
-       } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) {
-               /*
-                * Figure the total bytes to be added to the destination leaf.
-                */
-               count -= INT_GET(hdr1->count, ARCH_CONVERT);            /* number entries being moved */
-               space  = totallen - INT_GET(hdr1->namebytes, ARCH_CONVERT);
-               space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1);
-               space += count * (uint)sizeof(xfs_dir_leaf_entry_t);
-
-               /*
-                * leaf1 is the destination, compact it if it looks tight.
-                */
-               max  = INT_GET(hdr1->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t);
-               max -= INT_GET(hdr1->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t);
-               if (space > max) {
-                       xfs_dir_leaf_compact(state->args->trans, blk1->bp,
-                                                                0, 0);
-               }
-
-               /*
-                * Move low entries from leaf2 to high end of leaf1.
-                */
-               xfs_dir_leaf_moveents(leaf2, 0, leaf1, (int)INT_GET(hdr1->count, ARCH_CONVERT),
-                                            count, state->mp);
-
-               xfs_da_log_buf(state->args->trans, blk1->bp, 0,
-                                                  state->blocksize-1);
-               xfs_da_log_buf(state->args->trans, blk2->bp, 0,
-                                                  state->blocksize-1);
-       }
-
-       /*
-        * Copy out last hashval in each block for B-tree code.
-        */
-       blk1->hashval = INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
-       blk2->hashval = INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
-
-       /*
-        * Adjust the expected index for insertion.
-        * GROT: this doesn't work unless blk2 was originally empty.
-        */
-       if (!state->inleaf) {
-               blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT);
-       }
-}
-
-/*
- * Examine entries until we reduce the absolute difference in
- * byte usage between the two blocks to a minimum.
- * GROT: Is this really necessary?  With other than a 512 byte blocksize,
- * GROT: there will always be enough room in either block for a new entry.
- * GROT: Do a double-split for this case?
- */
-STATIC int
-xfs_dir_leaf_figure_balance(xfs_da_state_t *state,
-                                          xfs_da_state_blk_t *blk1,
-                                          xfs_da_state_blk_t *blk2,
-                                          int *countarg, int *namebytesarg)
-{
-       xfs_dir_leafblock_t *leaf1, *leaf2;
-       xfs_dir_leaf_hdr_t *hdr1, *hdr2;
-       xfs_dir_leaf_entry_t *entry;
-       int count, max, totallen, half;
-       int lastdelta, foundit, tmp;
-
-       /*
-        * Set up environment.
-        */
-       leaf1 = blk1->bp->data;
-       leaf2 = blk2->bp->data;
-       hdr1 = &leaf1->hdr;
-       hdr2 = &leaf2->hdr;
-       foundit = 0;
-       totallen = 0;
-
-       /*
-        * Examine entries until we reduce the absolute difference in
-        * byte usage between the two blocks to a minimum.
-        */
-       max = INT_GET(hdr1->count, ARCH_CONVERT) + INT_GET(hdr2->count, ARCH_CONVERT);
-       half  = (max+1) * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1);
-       half += INT_GET(hdr1->namebytes, ARCH_CONVERT) + INT_GET(hdr2->namebytes, ARCH_CONVERT) + state->args->namelen;
-       half /= 2;
-       lastdelta = state->blocksize;
-       entry = &leaf1->entries[0];
-       for (count = 0; count < max; entry++, count++) {
-
-#define XFS_DIR_ABS(A) (((A) < 0) ? -(A) : (A))
-               /*
-                * The new entry is in the first block, account for it.
-                */
-               if (count == blk1->index) {
-                       tmp = totallen + (uint)sizeof(*entry)
-                               + XFS_DIR_LEAF_ENTSIZE_BYNAME(state->args->namelen);
-                       if (XFS_DIR_ABS(half - tmp) > lastdelta)
-                               break;
-                       lastdelta = XFS_DIR_ABS(half - tmp);
-                       totallen = tmp;
-                       foundit = 1;
-               }
-
-               /*
-                * Wrap around into the second block if necessary.
-                */
-               if (count == INT_GET(hdr1->count, ARCH_CONVERT)) {
-                       leaf1 = leaf2;
-                       entry = &leaf1->entries[0];
-               }
-
-               /*
-                * Figure out if next leaf entry would be too much.
-                */
-               tmp = totallen + (uint)sizeof(*entry)
-                               + XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry);
-               if (XFS_DIR_ABS(half - tmp) > lastdelta)
-                       break;
-               lastdelta = XFS_DIR_ABS(half - tmp);
-               totallen = tmp;
-#undef XFS_DIR_ABS
-       }
-
-       /*
-        * Calculate the number of namebytes that will end up in lower block.
-        * If new entry not in lower block, fix up the count.
-        */
-       totallen -=
-               count * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1);
-       if (foundit) {
-               totallen -= (sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1) +
-                           state->args->namelen;
-       }
-
-       *countarg = count;
-       *namebytesarg = totallen;
-       return foundit;
-}
-
-/*========================================================================
- * Routines used for shrinking the Btree.
- *========================================================================*/
-
-/*
- * Check a leaf block and its neighbors to see if the block should be
- * collapsed into one or the other neighbor.  Always keep the block
- * with the smaller block number.
- * If the current block is over 50% full, don't try to join it, return 0.
- * If the block is empty, fill in the state structure and return 2.
- * If it can be collapsed, fill in the state structure and return 1.
- * If nothing can be done, return 0.
- */
-int
-xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_da_state_blk_t *blk;
-       xfs_da_blkinfo_t *info;
-       int count, bytes, forward, error, retval, i;
-       xfs_dablk_t blkno;
-       xfs_dabuf_t *bp;
-
-       /*
-        * Check for the degenerate case of the block being over 50% full.
-        * If so, it's not worth even looking to see if we might be able
-        * to coalesce with a sibling.
-        */
-       blk = &state->path.blk[ state->path.active-1 ];
-       info = blk->bp->data;
-       ASSERT(be16_to_cpu(info->magic) == XFS_DIR_LEAF_MAGIC);
-       leaf = (xfs_dir_leafblock_t *)info;
-       count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-       bytes = (uint)sizeof(xfs_dir_leaf_hdr_t) +
-               count * (uint)sizeof(xfs_dir_leaf_entry_t) +
-               count * ((uint)sizeof(xfs_dir_leaf_name_t)-1) +
-               INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
-       if (bytes > (state->blocksize >> 1)) {
-               *action = 0;    /* blk over 50%, don't try to join */
-               return 0;
-       }
-
-       /*
-        * Check for the degenerate case of the block being empty.
-        * If the block is empty, we'll simply delete it, no need to
-        * coalesce it with a sibling block.  We choose (arbitrarily)
-        * to merge with the forward block unless it is NULL.
-        */
-       if (count == 0) {
-               /*
-                * Make altpath point to the block we want to keep and
-                * path point to the block we want to drop (this one).
-                */
-               forward = (info->forw != 0);
-               memcpy(&state->altpath, &state->path, sizeof(state->path));
-               error = xfs_da_path_shift(state, &state->altpath, forward,
-                                                0, &retval);
-               if (error)
-                       return error;
-               if (retval) {
-                       *action = 0;
-               } else {
-                       *action = 2;
-               }
-               return 0;
-       }
-
-       /*
-        * Examine each sibling block to see if we can coalesce with
-        * at least 25% free space to spare.  We need to figure out
-        * whether to merge with the forward or the backward block.
-        * We prefer coalescing with the lower numbered sibling so as
-        * to shrink a directory over time.
-        */
-       forward = (be32_to_cpu(info->forw) < be32_to_cpu(info->back));  /* start with smaller blk num */
-       for (i = 0; i < 2; forward = !forward, i++) {
-               if (forward)
-                       blkno = be32_to_cpu(info->forw);
-               else
-                       blkno = be32_to_cpu(info->back);
-               if (blkno == 0)
-                       continue;
-               error = xfs_da_read_buf(state->args->trans, state->args->dp,
-                                                           blkno, -1, &bp,
-                                                           XFS_DATA_FORK);
-               if (error)
-                       return error;
-               ASSERT(bp != NULL);
-
-               leaf = (xfs_dir_leafblock_t *)info;
-               count  = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-               bytes  = state->blocksize - (state->blocksize>>2);
-               bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
-               leaf = bp->data;
-               ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-               count += INT_GET(leaf->hdr.count, ARCH_CONVERT);
-               bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
-               bytes -= count * ((uint)sizeof(xfs_dir_leaf_name_t) - 1);
-               bytes -= count * (uint)sizeof(xfs_dir_leaf_entry_t);
-               bytes -= (uint)sizeof(xfs_dir_leaf_hdr_t);
-               if (bytes >= 0)
-                       break;  /* fits with at least 25% to spare */
-
-               xfs_da_brelse(state->args->trans, bp);
-       }
-       if (i >= 2) {
-               *action = 0;
-               return 0;
-       }
-       xfs_da_buf_done(bp);
-
-       /*
-        * Make altpath point to the block we want to keep (the lower
-        * numbered block) and path point to the block we want to drop.
-        */
-       memcpy(&state->altpath, &state->path, sizeof(state->path));
-       if (blkno < blk->blkno) {
-               error = xfs_da_path_shift(state, &state->altpath, forward,
-                                                0, &retval);
-       } else {
-               error = xfs_da_path_shift(state, &state->path, forward,
-                                                0, &retval);
-       }
-       if (error)
-               return error;
-       if (retval) {
-               *action = 0;
-       } else {
-               *action = 1;
-       }
-       return 0;
-}
-
-/*
- * Remove a name from the leaf directory structure.
- *
- * Return 1 if leaf is less than 37% full, 0 if >= 37% full.
- * If two leaves are 37% full, when combined they will leave 25% free.
- */
-int
-xfs_dir_leaf_remove(xfs_trans_t *trans, xfs_dabuf_t *bp, int index)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_hdr_t *hdr;
-       xfs_dir_leaf_map_t *map;
-       xfs_dir_leaf_entry_t *entry;
-       xfs_dir_leaf_name_t *namest;
-       int before, after, smallest, entsize;
-       int tablesize, tmp, i;
-       xfs_mount_t *mp;
-
-       leaf = bp->data;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       hdr = &leaf->hdr;
-       mp = trans->t_mountp;
-       ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)));
-       ASSERT((index >= 0) && (index < INT_GET(hdr->count, ARCH_CONVERT)));
-       ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr)));
-       entry = &leaf->entries[index];
-       ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT));
-       ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
-
-       /*
-        * Scan through free region table:
-        *    check for adjacency of free'd entry with an existing one,
-        *    find smallest free region in case we need to replace it,
-        *    adjust any map that borders the entry table,
-        */
-       tablesize = INT_GET(hdr->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)
-                       + (uint)sizeof(xfs_dir_leaf_hdr_t);
-       map = &hdr->freemap[0];
-       tmp = INT_GET(map->size, ARCH_CONVERT);
-       before = after = -1;
-       smallest = XFS_DIR_LEAF_MAPSIZE - 1;
-       entsize = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry);
-       for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) {
-               ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
-               ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
-               if (INT_GET(map->base, ARCH_CONVERT) == tablesize) {
-                       INT_MOD(map->base, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t)));
-                       INT_MOD(map->size, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t));
-               }
-
-               if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == INT_GET(entry->nameidx, ARCH_CONVERT)) {
-                       before = i;
-               } else if (INT_GET(map->base, ARCH_CONVERT) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) {
-                       after = i;
-               } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) {
-                       tmp = INT_GET(map->size, ARCH_CONVERT);
-                       smallest = i;
-               }
-       }
-
-       /*
-        * Coalesce adjacent freemap regions,
-        * or replace the smallest region.
-        */
-       if ((before >= 0) || (after >= 0)) {
-               if ((before >= 0) && (after >= 0)) {
-                       map = &hdr->freemap[before];
-                       INT_MOD(map->size, ARCH_CONVERT, entsize);
-                       INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT));
-                       hdr->freemap[after].base = 0;
-                       hdr->freemap[after].size = 0;
-               } else if (before >= 0) {
-                       map = &hdr->freemap[before];
-                       INT_MOD(map->size, ARCH_CONVERT, entsize);
-               } else {
-                       map = &hdr->freemap[after];
-                       INT_COPY(map->base, entry->nameidx, ARCH_CONVERT);
-                       INT_MOD(map->size, ARCH_CONVERT, entsize);
-               }
-       } else {
-               /*
-                * Replace smallest region (if it is smaller than free'd entry)
-                */
-               map = &hdr->freemap[smallest];
-               if (INT_GET(map->size, ARCH_CONVERT) < entsize) {
-                       INT_COPY(map->base, entry->nameidx, ARCH_CONVERT);
-                       INT_SET(map->size, ARCH_CONVERT, entsize);
-               }
-       }
-
-       /*
-        * Did we remove the first entry?
-        */
-       if (INT_GET(entry->nameidx, ARCH_CONVERT) == INT_GET(hdr->firstused, ARCH_CONVERT))
-               smallest = 1;
-       else
-               smallest = 0;
-
-       /*
-        * Compress the remaining entries and zero out the removed stuff.
-        */
-       namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-       memset((char *)namest, 0, entsize);
-       xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize));
-
-       INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen));
-       tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t);
-       memmove(entry, entry + 1, tmp);
-       INT_MOD(hdr->count, ARCH_CONVERT, -1);
-       xfs_da_log_buf(trans, bp,
-           XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
-       entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
-       memset((char *)entry, 0, sizeof(xfs_dir_leaf_entry_t));
-
-       /*
-        * If we removed the first entry, re-find the first used byte
-        * in the name area.  Note that if the entry was the "firstused",
-        * then we don't have a "hole" in our block resulting from
-        * removing the name.
-        */
-       if (smallest) {
-               tmp = XFS_LBSIZE(mp);
-               entry = &leaf->entries[0];
-               for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) {
-                       ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT));
-                       ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
-                       if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp)
-                               tmp = INT_GET(entry->nameidx, ARCH_CONVERT);
-               }
-               INT_SET(hdr->firstused, ARCH_CONVERT, tmp);
-               if (!hdr->firstused)
-                       INT_SET(hdr->firstused, ARCH_CONVERT, tmp - 1);
-       } else {
-               hdr->holes = 1;         /* mark as needing compaction */
-       }
-
-       xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
-
-       /*
-        * Check if leaf is less than 50% full, caller may want to
-        * "join" the leaf with a sibling if so.
-        */
-       tmp  = (uint)sizeof(xfs_dir_leaf_hdr_t);
-       tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t);
-       tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1);
-       tmp += INT_GET(leaf->hdr.namebytes, ARCH_CONVERT);
-       if (tmp < mp->m_dir_magicpct)
-               return 1;                       /* leaf is < 37% full */
-       return 0;
-}
-
-/*
- * Move all the directory entries from drop_leaf into save_leaf.
- */
-void
-xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
-                                     xfs_da_state_blk_t *save_blk)
-{
-       xfs_dir_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf;
-       xfs_dir_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr;
-       xfs_mount_t *mp;
-       char *tmpbuffer;
-
-       /*
-        * Set up environment.
-        */
-       mp = state->mp;
-       ASSERT(drop_blk->magic == XFS_DIR_LEAF_MAGIC);
-       ASSERT(save_blk->magic == XFS_DIR_LEAF_MAGIC);
-       drop_leaf = drop_blk->bp->data;
-       save_leaf = save_blk->bp->data;
-       ASSERT(be16_to_cpu(drop_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       ASSERT(be16_to_cpu(save_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       drop_hdr = &drop_leaf->hdr;
-       save_hdr = &save_leaf->hdr;
-
-       /*
-        * Save last hashval from dying block for later Btree fixup.
-        */
-       drop_blk->hashval = INT_GET(drop_leaf->entries[ drop_leaf->hdr.count-1 ].hashval, ARCH_CONVERT);
-
-       /*
-        * Check if we need a temp buffer, or can we do it in place.
-        * Note that we don't check "leaf" for holes because we will
-        * always be dropping it, toosmall() decided that for us already.
-        */
-       if (save_hdr->holes == 0) {
-               /*
-                * dest leaf has no holes, so we add there.  May need
-                * to make some room in the entry array.
-                */
-               if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) {
-                       xfs_dir_leaf_moveents(drop_leaf, 0, save_leaf, 0,
-                                                (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
-               } else {
-                       xfs_dir_leaf_moveents(drop_leaf, 0,
-                                             save_leaf, INT_GET(save_hdr->count, ARCH_CONVERT),
-                                             (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
-               }
-       } else {
-               /*
-                * Destination has holes, so we make a temporary copy
-                * of the leaf and add them both to that.
-                */
-               tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP);
-               ASSERT(tmpbuffer != NULL);
-               memset(tmpbuffer, 0, state->blocksize);
-               tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer;
-               tmp_hdr = &tmp_leaf->hdr;
-               tmp_hdr->info = save_hdr->info; /* struct copy */
-               tmp_hdr->count = 0;
-               INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize);
-               if (!tmp_hdr->firstused)
-                       INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize - 1);
-               tmp_hdr->namebytes = 0;
-               if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) {
-                       xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0,
-                                                (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
-                       xfs_dir_leaf_moveents(save_leaf, 0,
-                                             tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
-                                             (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp);
-               } else {
-                       xfs_dir_leaf_moveents(save_leaf, 0, tmp_leaf, 0,
-                                                (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp);
-                       xfs_dir_leaf_moveents(drop_leaf, 0,
-                                             tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
-                                             (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
-               }
-               memcpy(save_leaf, tmp_leaf, state->blocksize);
-               kmem_free(tmpbuffer, state->blocksize);
-       }
-
-       xfs_da_log_buf(state->args->trans, save_blk->bp, 0,
-                                          state->blocksize - 1);
-
-       /*
-        * Copy out last hashval in each block for B-tree code.
-        */
-       save_blk->hashval = INT_GET(save_leaf->entries[ INT_GET(save_leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT);
-}
-
-/*========================================================================
- * Routines used for finding things in the Btree.
- *========================================================================*/
-
-/*
- * Look up a name in a leaf directory structure.
- * This is the internal routine, it uses the caller's buffer.
- *
- * Note that duplicate keys are allowed, but only check within the
- * current leaf node.  The Btree code must check in adjacent leaf nodes.
- *
- * Return in *index the index into the entry[] array of either the found
- * entry, or where the entry should have been (insert before that entry).
- *
- * Don't change the args->inumber unless we find the filename.
- */
-int
-xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args, int *index)
-{
-       xfs_dir_leafblock_t *leaf;
-       xfs_dir_leaf_entry_t *entry;
-       xfs_dir_leaf_name_t *namest;
-       int probe, span;
-       xfs_dahash_t hashval;
-
-       leaf = bp->data;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) < (XFS_LBSIZE(args->dp->i_mount)/8));
-
-       /*
-        * Binary search.  (note: small blocks will skip this loop)
-        */
-       hashval = args->hashval;
-       probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2;
-       for (entry = &leaf->entries[probe]; span > 4;
-                  entry = &leaf->entries[probe]) {
-               span /= 2;
-               if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)
-                       probe += span;
-               else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval)
-                       probe -= span;
-               else
-                       break;
-       }
-       ASSERT((probe >= 0) && \
-              ((!leaf->hdr.count) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
-       ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval));
-
-       /*
-        * Since we may have duplicate hashval's, find the first matching
-        * hashval in the leaf.
-        */
-       while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) >= hashval)) {
-               entry--;
-               probe--;
-       }
-       while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) {
-               entry++;
-               probe++;
-       }
-       if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) {
-               *index = probe;
-               ASSERT(args->oknoent);
-               return XFS_ERROR(ENOENT);
-       }
-
-       /*
-        * Duplicate keys may be present, so search all of them for a match.
-        */
-       while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)) {
-               namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-               if (entry->namelen == args->namelen &&
-                   namest->name[0] == args->name[0] &&
-                   memcmp(args->name, namest->name, args->namelen) == 0) {
-                       XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args->inumber);
-                       *index = probe;
-                       return XFS_ERROR(EEXIST);
-               }
-               entry++;
-               probe++;
-       }
-       *index = probe;
-       ASSERT(probe == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent);
-       return XFS_ERROR(ENOENT);
-}
-
-/*========================================================================
- * Utility routines.
- *========================================================================*/
-
-/*
- * Move the indicated entries from one leaf to another.
- * NOTE: this routine modifies both source and destination leaves.
- */
-/* ARGSUSED */
-STATIC void
-xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s,
-                     xfs_dir_leafblock_t *leaf_d, int start_d,
-                     int count, xfs_mount_t *mp)
-{
-       xfs_dir_leaf_hdr_t *hdr_s, *hdr_d;
-       xfs_dir_leaf_entry_t *entry_s, *entry_d;
-       int tmp, i;
-
-       /*
-        * Check for nothing to do.
-        */
-       if (count == 0)
-               return;
-
-       /*
-        * Set up environment.
-        */
-       ASSERT(be16_to_cpu(leaf_s->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       ASSERT(be16_to_cpu(leaf_d->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       hdr_s = &leaf_s->hdr;
-       hdr_d = &leaf_d->hdr;
-       ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) && (INT_GET(hdr_s->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)));
-       ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >=
-               ((INT_GET(hdr_s->count, ARCH_CONVERT)*sizeof(*entry_s))+sizeof(*hdr_s)));
-       ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8));
-       ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >=
-               ((INT_GET(hdr_d->count, ARCH_CONVERT)*sizeof(*entry_d))+sizeof(*hdr_d)));
-
-       ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT));
-       ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT));
-       ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT));
-
-       /*
-        * Move the entries in the destination leaf up to make a hole?
-        */
-       if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) {
-               tmp  = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d;
-               tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
-               entry_s = &leaf_d->entries[start_d];
-               entry_d = &leaf_d->entries[start_d + count];
-               memcpy(entry_d, entry_s, tmp);
-       }
-
-       /*
-        * Copy all entry's in the same (sorted) order,
-        * but allocate filenames packed and in sequence.
-        */
-       entry_s = &leaf_s->entries[start_s];
-       entry_d = &leaf_d->entries[start_d];
-       for (i = 0; i < count; entry_s++, entry_d++, i++) {
-               ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) >= INT_GET(hdr_s->firstused, ARCH_CONVERT));
-               tmp = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry_s);
-               INT_MOD(hdr_d->firstused, ARCH_CONVERT, -(tmp));
-               entry_d->hashval = entry_s->hashval; /* INT_: direct copy */
-               INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT);
-               entry_d->namelen = entry_s->namelen;
-               ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
-               memcpy(XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)),
-                      XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), tmp);
-               ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
-               memset((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
-                     0, tmp);
-               INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen));
-               INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen);
-               INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
-               INT_MOD(hdr_d->count, ARCH_CONVERT, +1);
-               tmp  = INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)
-                               + (uint)sizeof(xfs_dir_leaf_hdr_t);
-               ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp);
-
-       }
-
-       /*
-        * Zero out the entries we just copied.
-        */
-       if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) {
-               tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
-               entry_s = &leaf_s->entries[start_s];
-               ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
-               memset((char *)entry_s, 0, tmp);
-       } else {
-               /*
-                * Move the remaining entries down to fill the hole,
-                * then zero the entries at the top.
-                */
-               tmp  = INT_GET(hdr_s->count, ARCH_CONVERT) - count;
-               tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
-               entry_s = &leaf_s->entries[start_s + count];
-               entry_d = &leaf_s->entries[start_s];
-               memcpy(entry_d, entry_s, tmp);
-
-               tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
-               entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)];
-               ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
-               memset((char *)entry_s, 0, tmp);
-       }
-
-       /*
-        * Fill in the freemap information
-        */
-       INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_hdr_t));
-       INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t));
-       INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
-       INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, (hdr_d->freemap[2].base = 0));
-       INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, (hdr_d->freemap[2].size = 0));
-       hdr_s->holes = 1;       /* leaf may not be compact */
-}
-
-/*
- * Compare two leaf blocks "order".
- */
-int
-xfs_dir_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp)
-{
-       xfs_dir_leafblock_t *leaf1, *leaf2;
-
-       leaf1 = leaf1_bp->data;
-       leaf2 = leaf2_bp->data;
-       ASSERT((be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC) &&
-              (be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC));
-       if ((INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) &&
-           ((INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) <
-             INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) ||
-            (INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) <
-             INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) {
-               return 1;
-       }
-       return 0;
-}
-
-/*
- * Pick up the last hashvalue from a leaf block.
- */
-xfs_dahash_t
-xfs_dir_leaf_lasthash(xfs_dabuf_t *bp, int *count)
-{
-       xfs_dir_leafblock_t *leaf;
-
-       leaf = bp->data;
-       ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC);
-       if (count)
-               *count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
-       if (!leaf->hdr.count)
-               return(0);
-       return(INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT));
-}
-
-/*
- * Copy out directory entries for getdents(), for leaf directories.
- */
-int
-xfs_dir_leaf_getdents_int(
-       xfs_dabuf_t     *bp,
-       xfs_inode_t     *dp,
-       xfs_dablk_t     bno,
-       uio_t           *uio,
-       int             *eobp,
-       xfs_dirent_t    *dbp,
-       xfs_dir_put_t   put,
-       xfs_daddr_t             nextda)
-{
-       xfs_dir_leafblock_t     *leaf;
-       xfs_dir_leaf_entry_t    *entry;
-       xfs_dir_leaf_name_t     *namest;
-       int                     entno, want_entno, i, nextentno;
-       xfs_mount_t             *mp;
-       xfs_dahash_t            cookhash;
-       xfs_dahash_t            nexthash = 0;
-#if (BITS_PER_LONG == 32)
-       xfs_dahash_t            lasthash = XFS_DA_MAXHASH;
-#endif
-       xfs_dir_put_args_t      p;
-
-       mp = dp->i_mount;
-       leaf = bp->data;
-       if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) {
-               *eobp = 1;
-               return XFS_ERROR(ENOENT);       /* XXX wrong code */
-       }
-
-       want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset);
-
-       cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset);
-
-       xfs_dir_trace_g_dul("leaf: start", dp, uio, leaf);
-
-       /*
-        * Re-find our place.
-        */
-       for (i = entno = 0, entry = &leaf->entries[0];
-                    i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
-                            entry++, i++) {
-
-               namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
-                                   INT_GET(entry->nameidx, ARCH_CONVERT));
-
-               if (unlikely(
-                   ((char *)namest < (char *)leaf) ||
-                   ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) {
-                       XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(1)",
-                                            XFS_ERRLEVEL_LOW, mp, leaf);
-                       xfs_dir_trace_g_du("leaf: corrupted", dp, uio);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-               if (INT_GET(entry->hashval, ARCH_CONVERT) >= cookhash) {
-                       if (   entno < want_entno
-                           && INT_GET(entry->hashval, ARCH_CONVERT)
-                                                       == cookhash) {
-                               /*
-                                * Trying to get to a particular offset in a
-                                * run of equal-hashval entries.
-                                */
-                               entno++;
-                       } else if (   want_entno > 0
-                                  && entno == want_entno
-                                  && INT_GET(entry->hashval, ARCH_CONVERT)
-                                                       == cookhash) {
-                               break;
-                       } else {
-                               entno = 0;
-                               break;
-                       }
-               }
-       }
-
-       if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) {
-               xfs_dir_trace_g_du("leaf: hash not found", dp, uio);
-               if (!leaf->hdr.info.forw)
-                       uio->uio_offset =
-                               XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH);
-               /*
-                * Don't set uio_offset if there's another block:
-                * the node code will be setting uio_offset anyway.
-                */
-               *eobp = 0;
-               return 0;
-       }
-       xfs_dir_trace_g_due("leaf: hash found", dp, uio, entry);
-
-       p.dbp = dbp;
-       p.put = put;
-       p.uio = uio;
-
-       /*
-        * We're synchronized, start copying entries out to the user.
-        */
-       for (; entno >= 0 && i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
-                            entry++, i++, (entno = nextentno)) {
-               int lastresid=0, retval;
-               xfs_dircook_t lastoffset;
-               xfs_dahash_t thishash;
-
-               /*
-                * Check for a damaged directory leaf block and pick up
-                * the inode number from this entry.
-                */
-               namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
-                                   INT_GET(entry->nameidx, ARCH_CONVERT));
-
-               if (unlikely(
-                   ((char *)namest < (char *)leaf) ||
-                   ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) {
-                       XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(2)",
-                                            XFS_ERRLEVEL_LOW, mp, leaf);
-                       xfs_dir_trace_g_du("leaf: corrupted", dp, uio);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-
-               xfs_dir_trace_g_duc("leaf: middle cookie  ",
-                                                  dp, uio, p.cook.o);
-
-               if (i < (INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1)) {
-                       nexthash = INT_GET(entry[1].hashval, ARCH_CONVERT);
-
-                       if (nexthash == INT_GET(entry->hashval, ARCH_CONVERT))
-                               nextentno = entno + 1;
-                       else
-                               nextentno = 0;
-                       XFS_PUT_COOKIE(p.cook, mp, bno, nextentno, nexthash);
-                       xfs_dir_trace_g_duc("leaf: middle cookie  ",
-                                                  dp, uio, p.cook.o);
-
-               } else if ((thishash = be32_to_cpu(leaf->hdr.info.forw))) {
-                       xfs_dabuf_t *bp2;
-                       xfs_dir_leafblock_t *leaf2;
-
-                       ASSERT(nextda != -1);
-
-                       retval = xfs_da_read_buf(dp->i_transp, dp, thishash,
-                                                nextda, &bp2, XFS_DATA_FORK);
-                       if (retval)
-                               return retval;
-
-                       ASSERT(bp2 != NULL);
-
-                       leaf2 = bp2->data;
-
-                       if (unlikely(
-                              (be16_to_cpu(leaf2->hdr.info.magic)
-                                               != XFS_DIR_LEAF_MAGIC)
-                           || (be32_to_cpu(leaf2->hdr.info.back)
-                                               != bno))) {     /* GROT */
-                               XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(3)",
-                                                    XFS_ERRLEVEL_LOW, mp,
-                                                    leaf2);
-                               xfs_da_brelse(dp->i_transp, bp2);
-
-                               return XFS_ERROR(EFSCORRUPTED);
-                       }
-
-                       nexthash = INT_GET(leaf2->entries[0].hashval,
-                                                               ARCH_CONVERT);
-                       nextentno = -1;
-                       XFS_PUT_COOKIE(p.cook, mp, thishash, 0, nexthash);
-                       xfs_da_brelse(dp->i_transp, bp2);
-                       xfs_dir_trace_g_duc("leaf: next blk cookie",
-                                                  dp, uio, p.cook.o);
-               } else {
-                       nextentno = -1;
-                       XFS_PUT_COOKIE(p.cook, mp, 0, 0, XFS_DA_MAXHASH);
-               }
-
-               /*
-                * Save off the cookie so we can fall back should the
-                * 'put' into the outgoing buffer fails.  To handle a run
-                * of equal-hashvals, the off_t structure on 64bit
-                * builds has entno built into the cookie to ID the
-                * entry.  On 32bit builds, we only have space for the
-                * hashval so we can't ID specific entries within a group
-                * of same hashval entries.   For this, lastoffset is set
-                * to the first in the run of equal hashvals so we don't
-                * include any entries unless we can include all entries
-                * that share the same hashval.  Hopefully the buffer
-                * provided is big enough to handle it (see pv763517).
-                */
-#if (BITS_PER_LONG == 32)
-               if ((thishash = INT_GET(entry->hashval, ARCH_CONVERT))
-                                                               != lasthash) {
-                       XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash);
-                       lastresid = uio->uio_resid;
-                       lasthash = thishash;
-               } else {
-                       xfs_dir_trace_g_duc("leaf: DUP COOKIES, skipped",
-                                                  dp, uio, p.cook.o);
-               }
-#else
-               thishash = INT_GET(entry->hashval, ARCH_CONVERT);
-               XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash);
-               lastresid = uio->uio_resid;
-#endif /* BITS_PER_LONG == 32 */
-
-               /*
-                * Put the current entry into the outgoing buffer.  If we fail
-                * then restore the UIO to the first entry in the current
-                * run of equal-hashval entries (probably one 1 entry long).
-                */
-               p.ino = XFS_GET_DIR_INO8(namest->inumber);
-#if XFS_BIG_INUMS
-               p.ino += mp->m_inoadd;
-#endif
-               p.name = (char *)namest->name;
-               p.namelen = entry->namelen;
-
-               retval = p.put(&p);
-
-               if (!p.done) {
-                       uio->uio_offset = lastoffset.o;
-                       uio->uio_resid = lastresid;
-
-                       *eobp = 1;
-
-                       xfs_dir_trace_g_du("leaf: E-O-B", dp, uio);
-
-                       return retval;
-               }
-       }
-
-       uio->uio_offset = p.cook.o;
-
-       *eobp = 0;
-
-       xfs_dir_trace_g_du("leaf: E-O-F", dp, uio);
-
-       return 0;
-}
-
-/*
- * Format a dirent64 structure and copy it out the the user's buffer.
- */
-int
-xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa)
-{
-       iovec_t *iovp;
-       int reclen, namelen;
-       xfs_dirent_t *idbp;
-       uio_t *uio;
-
-       namelen = pa->namelen;
-       reclen = DIRENTSIZE(namelen);
-       uio = pa->uio;
-       if (reclen > uio->uio_resid) {
-               pa->done = 0;
-               return 0;
-       }
-       iovp = uio->uio_iov;
-       idbp = (xfs_dirent_t *)iovp->iov_base;
-       iovp->iov_base = (char *)idbp + reclen;
-       iovp->iov_len -= reclen;
-       uio->uio_resid -= reclen;
-       idbp->d_reclen = reclen;
-       idbp->d_ino = pa->ino;
-       idbp->d_off = pa->cook.o;
-       idbp->d_name[namelen] = '\0';
-       pa->done = 1;
-       memcpy(idbp->d_name, pa->name, namelen);
-       return 0;
-}
-
-/*
- * Format a dirent64 structure and copy it out the the user's buffer.
- */
-int
-xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa)
-{
-       int             retval, reclen, namelen;
-       xfs_dirent_t    *idbp;
-       uio_t           *uio;
-
-       namelen = pa->namelen;
-       reclen = DIRENTSIZE(namelen);
-       uio = pa->uio;
-       if (reclen > uio->uio_resid) {
-               pa->done = 0;
-               return 0;
-       }
-       idbp = pa->dbp;
-       idbp->d_reclen = reclen;
-       idbp->d_ino = pa->ino;
-       idbp->d_off = pa->cook.o;
-       idbp->d_name[namelen] = '\0';
-       memcpy(idbp->d_name, pa->name, namelen);
-       retval = uio_read((caddr_t)idbp, reclen, uio);
-       pa->done = (retval == 0);
-       return retval;
-}
diff --git a/fs/xfs/xfs_dir_leaf.h b/fs/xfs/xfs_dir_leaf.h
deleted file mode 100644 (file)
index eb8cd9a..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef __XFS_DIR_LEAF_H__
-#define        __XFS_DIR_LEAF_H__
-
-/*
- * Directory layout, internal structure, access macros, etc.
- *
- * Large directories are structured around Btrees where all the data
- * elements are in the leaf nodes.  Filenames are hashed into an int,
- * then that int is used as the index into the Btree.  Since the hashval
- * of a filename may not be unique, we may have duplicate keys.  The
- * internal links in the Btree are logical block offsets into the file.
- */
-
-struct uio;
-struct xfs_bmap_free;
-struct xfs_dabuf;
-struct xfs_da_args;
-struct xfs_da_state;
-struct xfs_da_state_blk;
-struct xfs_dir_put_args;
-struct xfs_inode;
-struct xfs_mount;
-struct xfs_trans;
-
-/*========================================================================
- * Directory Structure when equal to XFS_LBSIZE(mp) bytes.
- *========================================================================*/
-
-/*
- * This is the structure of the leaf nodes in the Btree.
- *
- * Struct leaf_entry's are packed from the top.  Names grow from the bottom
- * but are not packed.  The freemap contains run-length-encoded entries
- * for the free bytes after the leaf_entry's, but only the N largest such,
- * smaller runs are dropped.  When the freemap doesn't show enough space
- * for an allocation, we compact the namelist area and try again.  If we
- * still don't have enough space, then we have to split the block.
- *
- * Since we have duplicate hash keys, for each key that matches, compare
- * the actual string.  The root and intermediate node search always takes
- * the first-in-the-block key match found, so we should only have to work
- * "forw"ard.  If none matches, continue with the "forw"ard leaf nodes
- * until the hash key changes or the filename is found.
- *
- * The parent directory and the self-pointer are explicitly represented
- * (ie: there are entries for "." and "..").
- *
- * Note that the count being a __uint16_t limits us to something like a
- * blocksize of 1.3MB in the face of worst case (short) filenames.
- */
-#define XFS_DIR_LEAF_MAPSIZE   3       /* how many freespace slots */
-
-typedef struct xfs_dir_leaf_map {      /* RLE map of free bytes */
-       __uint16_t      base;           /* base of free region */
-       __uint16_t      size;           /* run length of free region */
-} xfs_dir_leaf_map_t;
-
-typedef struct xfs_dir_leaf_hdr {      /* constant-structure header block */
-       xfs_da_blkinfo_t info;          /* block type, links, etc. */
-       __uint16_t      count;          /* count of active leaf_entry's */
-       __uint16_t      namebytes;      /* num bytes of name strings stored */
-       __uint16_t      firstused;      /* first used byte in name area */
-       __uint8_t       holes;          /* != 0 if blk needs compaction */
-       __uint8_t       pad1;
-       xfs_dir_leaf_map_t freemap[XFS_DIR_LEAF_MAPSIZE];
-} xfs_dir_leaf_hdr_t;
-
-typedef struct xfs_dir_leaf_entry {    /* sorted on key, not name */
-       xfs_dahash_t    hashval;        /* hash value of name */
-       __uint16_t      nameidx;        /* index into buffer of name */
-       __uint8_t       namelen;        /* length of name string */
-       __uint8_t       pad2;
-} xfs_dir_leaf_entry_t;
-
-typedef struct xfs_dir_leaf_name {
-       xfs_dir_ino_t   inumber;        /* inode number for this key */
-       __uint8_t       name[1];        /* name string itself */
-} xfs_dir_leaf_name_t;
-
-typedef struct xfs_dir_leafblock {
-       xfs_dir_leaf_hdr_t      hdr;    /* constant-structure header block */
-       xfs_dir_leaf_entry_t    entries[1];     /* var sized array */
-       xfs_dir_leaf_name_t     namelist[1];    /* grows from bottom of buf */
-} xfs_dir_leafblock_t;
-
-/*
- * Length of name for which a 512-byte block filesystem
- * can get a double split.
- */
-#define        XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN       \
-       (512 - (uint)sizeof(xfs_dir_leaf_hdr_t) - \
-        (uint)sizeof(xfs_dir_leaf_entry_t) * 2 - \
-        (uint)sizeof(xfs_dir_leaf_name_t) * 2 - (MAXNAMELEN - 2) + 1 + 1)
-
-typedef int (*xfs_dir_put_t)(struct xfs_dir_put_args *pa);
-
-typedef union {
-       xfs_off_t               o;              /* offset (cookie) */
-       /*
-        * Watch the order here (endian-ness dependent).
-        */
-       struct {
-#ifndef XFS_NATIVE_HOST
-               xfs_dahash_t    h;      /* hash value */
-               __uint32_t      be;     /* block and entry */
-#else
-               __uint32_t      be;     /* block and entry */
-               xfs_dahash_t    h;      /* hash value */
-#endif /* XFS_NATIVE_HOST */
-       } s;
-} xfs_dircook_t;
-
-#define        XFS_PUT_COOKIE(c,mp,bno,entry,hash)     \
-       ((c).s.be = XFS_DA_MAKE_BNOENTRY(mp, bno, entry), (c).s.h = (hash))
-
-typedef struct xfs_dir_put_args {
-       xfs_dircook_t   cook;           /* cookie of (next) entry */
-       xfs_intino_t    ino;            /* inode number */
-       struct xfs_dirent *dbp;         /* buffer pointer */
-       char            *name;          /* directory entry name */
-       int             namelen;        /* length of name */
-       int             done;           /* output: set if value was stored */
-       xfs_dir_put_t   put;            /* put function ptr (i/o) */
-       struct uio      *uio;           /* uio control structure */
-} xfs_dir_put_args_t;
-
-#define XFS_DIR_LEAF_ENTSIZE_BYNAME(len)       \
-       xfs_dir_leaf_entsize_byname(len)
-static inline int xfs_dir_leaf_entsize_byname(int len)
-{
-       return (uint)sizeof(xfs_dir_leaf_name_t)-1 + len;
-}
-
-#define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry)    \
-       xfs_dir_leaf_entsize_byentry(entry)
-static inline int xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry)
-{
-       return (uint)sizeof(xfs_dir_leaf_name_t)-1 + (entry)->namelen;
-}
-
-#define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset)  \
-       xfs_dir_leaf_namestruct(leafp,offset)
-static inline xfs_dir_leaf_name_t *
-xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset)
-{
-       return (xfs_dir_leaf_name_t *)&((char *)(leafp))[offset];
-}
-
-/*========================================================================
- * Function prototypes for the kernel.
- *========================================================================*/
-
-/*
- * Internal routines when dirsize < XFS_LITINO(mp).
- */
-int xfs_dir_shortform_create(struct xfs_da_args *args, xfs_ino_t parent);
-int xfs_dir_shortform_addname(struct xfs_da_args *args);
-int xfs_dir_shortform_lookup(struct xfs_da_args *args);
-int xfs_dir_shortform_to_leaf(struct xfs_da_args *args);
-int xfs_dir_shortform_removename(struct xfs_da_args *args);
-int xfs_dir_shortform_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp,
-                              struct xfs_dirent *dbp, xfs_dir_put_t put);
-int xfs_dir_shortform_replace(struct xfs_da_args *args);
-
-/*
- * Internal routines when dirsize == XFS_LBSIZE(mp).
- */
-int xfs_dir_leaf_to_node(struct xfs_da_args *args);
-int xfs_dir_leaf_to_shortform(struct xfs_da_args *args);
-
-/*
- * Routines used for growing the Btree.
- */
-int    xfs_dir_leaf_split(struct xfs_da_state *state,
-                                 struct xfs_da_state_blk *oldblk,
-                                 struct xfs_da_state_blk *newblk);
-int    xfs_dir_leaf_add(struct xfs_dabuf *leaf_buffer,
-                               struct xfs_da_args *args, int insertion_index);
-int    xfs_dir_leaf_addname(struct xfs_da_args *args);
-int    xfs_dir_leaf_lookup_int(struct xfs_dabuf *leaf_buffer,
-                                      struct xfs_da_args *args,
-                                      int *index_found_at);
-int    xfs_dir_leaf_remove(struct xfs_trans *trans,
-                                  struct xfs_dabuf *leaf_buffer,
-                                  int index_to_remove);
-int    xfs_dir_leaf_getdents_int(struct xfs_dabuf *bp, struct xfs_inode *dp,
-                                        xfs_dablk_t bno, struct uio *uio,
-                                        int *eobp, struct xfs_dirent *dbp,
-                                        xfs_dir_put_t put, xfs_daddr_t nextda);
-
-/*
- * Routines used for shrinking the Btree.
- */
-int    xfs_dir_leaf_toosmall(struct xfs_da_state *state, int *retval);
-void   xfs_dir_leaf_unbalance(struct xfs_da_state *state,
-                                            struct xfs_da_state_blk *drop_blk,
-                                            struct xfs_da_state_blk *save_blk);
-
-/*
- * Utility routines.
- */
-uint   xfs_dir_leaf_lasthash(struct xfs_dabuf *bp, int *count);
-int    xfs_dir_leaf_order(struct xfs_dabuf *leaf1_bp,
-                                 struct xfs_dabuf *leaf2_bp);
-int    xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa);
-int    xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa);
-int    xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
-
-/*
- * Global data.
- */
-extern xfs_dahash_t    xfs_dir_hash_dot, xfs_dir_hash_dotdot;
-
-#endif /* __XFS_DIR_LEAF_H__ */
diff --git a/fs/xfs/xfs_dir_sf.h b/fs/xfs/xfs_dir_sf.h
deleted file mode 100644 (file)
index 5b20b4d..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2000,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef __XFS_DIR_SF_H__
-#define        __XFS_DIR_SF_H__
-
-/*
- * Directory layout when stored internal to an inode.
- *
- * Small directories are packed as tightly as possible so as to
- * fit into the literal area of the inode.
- */
-
-typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t;
-
-/*
- * The parent directory has a dedicated field, and the self-pointer must
- * be calculated on the fly.
- *
- * Entries are packed toward the top as tight as possible.  The header
- * and the elements much be memcpy'd out into a work area to get correct
- * alignment for the inode number fields.
- */
-typedef struct xfs_dir_sf_hdr {                /* constant-structure header block */
-       xfs_dir_ino_t   parent;         /* parent dir inode number */
-       __uint8_t       count;          /* count of active entries */
-} xfs_dir_sf_hdr_t;
-
-typedef struct xfs_dir_sf_entry {
-       xfs_dir_ino_t   inumber;        /* referenced inode number */
-       __uint8_t       namelen;        /* actual length of name (no NULL) */
-       __uint8_t       name[1];        /* name */
-} xfs_dir_sf_entry_t;
-
-typedef struct xfs_dir_shortform {
-       xfs_dir_sf_hdr_t        hdr;
-       xfs_dir_sf_entry_t      list[1];        /* variable sized array */
-} xfs_dir_shortform_t;
-
-/*
- * We generate this then sort it, so that readdirs are returned in
- * hash-order.  Else seekdir won't work.
- */
-typedef struct xfs_dir_sf_sort {
-       __uint8_t       entno;          /* .=0, ..=1, else entry# + 2 */
-       __uint8_t       seqno;          /* sequence # with same hash value */
-       __uint8_t       namelen;        /* length of name value (no null) */
-       xfs_dahash_t    hash;           /* this entry's hash value */
-       xfs_intino_t    ino;            /* this entry's inode number */
-       char            *name;          /* name value, pointer into buffer */
-} xfs_dir_sf_sort_t;
-
-#define        XFS_DIR_SF_GET_DIRINO(from,to)  xfs_dir_sf_get_dirino(from, to)
-static inline void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to)
-{
-       *(to) = XFS_GET_DIR_INO8(*from);
-}
-
-#define        XFS_DIR_SF_PUT_DIRINO(from,to)  xfs_dir_sf_put_dirino(from, to)
-static inline void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to)
-{
-       XFS_PUT_DIR_INO8(*(from), *(to));
-}
-
-#define XFS_DIR_SF_ENTSIZE_BYNAME(len) xfs_dir_sf_entsize_byname(len)
-static inline int xfs_dir_sf_entsize_byname(int len)
-{
-       return (uint)sizeof(xfs_dir_sf_entry_t)-1 + (len);
-}
-
-#define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep)       xfs_dir_sf_entsize_byentry(sfep)
-static inline int xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep)
-{
-       return (uint)sizeof(xfs_dir_sf_entry_t)-1 + (sfep)->namelen;
-}
-
-#define XFS_DIR_SF_NEXTENTRY(sfep)             xfs_dir_sf_nextentry(sfep)
-static inline xfs_dir_sf_entry_t *xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep)
-{
-       return (xfs_dir_sf_entry_t *) \
-               ((char *)(sfep) + XFS_DIR_SF_ENTSIZE_BYENTRY(sfep));
-}
-
-#define XFS_DIR_SF_ALLFIT(count,totallen)      \
-       xfs_dir_sf_allfit(count,totallen)
-static inline int xfs_dir_sf_allfit(int count, int totallen)
-{
-       return ((uint)sizeof(xfs_dir_sf_hdr_t) + \
-              ((uint)sizeof(xfs_dir_sf_entry_t)-1)*(count) + (totallen));
-}
-
-#if defined(XFS_DIR_TRACE)
-
-/*
- * Kernel tracing support for directories.
- */
-struct uio;
-struct xfs_inode;
-struct xfs_da_intnode;
-struct xfs_dinode;
-struct xfs_dir_leafblock;
-struct xfs_dir_leaf_entry;
-
-#define        XFS_DIR_TRACE_SIZE      4096    /* size of global trace buffer */
-extern ktrace_t        *xfs_dir_trace_buf;
-
-/*
- * Trace record types.
- */
-#define        XFS_DIR_KTRACE_G_DU     1       /* dp, uio */
-#define        XFS_DIR_KTRACE_G_DUB    2       /* dp, uio, bno */
-#define        XFS_DIR_KTRACE_G_DUN    3       /* dp, uio, node */
-#define        XFS_DIR_KTRACE_G_DUL    4       /* dp, uio, leaf */
-#define        XFS_DIR_KTRACE_G_DUE    5       /* dp, uio, leaf entry */
-#define        XFS_DIR_KTRACE_G_DUC    6       /* dp, uio, cookie */
-
-void xfs_dir_trace_g_du(char *where, struct xfs_inode *dp, struct uio *uio);
-void xfs_dir_trace_g_dub(char *where, struct xfs_inode *dp, struct uio *uio,
-                             xfs_dablk_t bno);
-void xfs_dir_trace_g_dun(char *where, struct xfs_inode *dp, struct uio *uio,
-                             struct xfs_da_intnode *node);
-void xfs_dir_trace_g_dul(char *where, struct xfs_inode *dp, struct uio *uio,
-                             struct xfs_dir_leafblock *leaf);
-void xfs_dir_trace_g_due(char *where, struct xfs_inode *dp, struct uio *uio,
-                             struct xfs_dir_leaf_entry *entry);
-void xfs_dir_trace_g_duc(char *where, struct xfs_inode *dp, struct uio *uio,
-                             xfs_off_t cookie);
-void xfs_dir_trace_enter(int type, char *where,
-                            void *a0, void *a1, void *a2, void *a3,
-                            void *a4, void *a5, void *a6, void *a7,
-                            void *a8, void *a9, void *a10, void *a11);
-#else
-#define        xfs_dir_trace_g_du(w,d,u)
-#define        xfs_dir_trace_g_dub(w,d,u,b)
-#define        xfs_dir_trace_g_dun(w,d,u,n)
-#define        xfs_dir_trace_g_dul(w,d,u,l)
-#define        xfs_dir_trace_g_due(w,d,u,e)
-#define        xfs_dir_trace_g_duc(w,d,u,c)
-#endif /* DEBUG */
-
-#endif /* __XFS_DIR_SF_H__ */
index 00b1540f8108c71ba5d7ce40aa53296f5254fb4c..4e7865ad6f0ee74fe83a08d6f53a6a21d0c4dd2e 100644 (file)
@@ -189,6 +189,6 @@ typedef enum {
 #define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0)
 
 
-extern struct bhv_vfsops xfs_dmops;
+extern struct bhv_module_vfsops xfs_dmops;
 
 #endif  /* __XFS_DMAPI_H__ */
index 629795b3b3d5987f937a7ff15f3f81fc21dc222a..1e4a35ddf7f98d0b97266391355ed209fcf2e1ec 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
index 2a21c5024017374960c40efcfd02a4488d9735b6..b95681b03d816087d9eb94a4aada2f3fe0f952de 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
index f19282ec8549c13d21cd5a8469ffd9b507c3a8c4..6cf6d8769b975902c290a4485372b9b507793aa1 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
@@ -293,6 +292,62 @@ xfs_efi_init(xfs_mount_t   *mp,
        return (efip);
 }
 
+/*
+ * Copy an EFI format buffer from the given buf, and into the destination
+ * EFI format structure.
+ * The given buffer can be in 32 bit or 64 bit form (which has different padding),
+ * one of which will be the native format for this kernel.
+ * It will handle the conversion of formats if necessary.
+ */
+int
+xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
+{
+       xfs_efi_log_format_t *src_efi_fmt = (xfs_efi_log_format_t *)buf->i_addr;
+       uint i;
+       uint len = sizeof(xfs_efi_log_format_t) + 
+               (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t);  
+       uint len32 = sizeof(xfs_efi_log_format_32_t) + 
+               (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_32_t);  
+       uint len64 = sizeof(xfs_efi_log_format_64_t) + 
+               (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_64_t);  
+
+       if (buf->i_len == len) {
+               memcpy((char *)dst_efi_fmt, (char*)src_efi_fmt, len);
+               return 0;
+       } else if (buf->i_len == len32) {
+               xfs_efi_log_format_32_t *src_efi_fmt_32 =
+                       (xfs_efi_log_format_32_t *)buf->i_addr;
+
+               dst_efi_fmt->efi_type     = src_efi_fmt_32->efi_type;
+               dst_efi_fmt->efi_size     = src_efi_fmt_32->efi_size;
+               dst_efi_fmt->efi_nextents = src_efi_fmt_32->efi_nextents;
+               dst_efi_fmt->efi_id       = src_efi_fmt_32->efi_id;
+               for (i = 0; i < dst_efi_fmt->efi_nextents; i++) {
+                       dst_efi_fmt->efi_extents[i].ext_start =
+                               src_efi_fmt_32->efi_extents[i].ext_start;
+                       dst_efi_fmt->efi_extents[i].ext_len =
+                               src_efi_fmt_32->efi_extents[i].ext_len;
+               }
+               return 0;
+       } else if (buf->i_len == len64) {
+               xfs_efi_log_format_64_t *src_efi_fmt_64 =
+                       (xfs_efi_log_format_64_t *)buf->i_addr;
+
+               dst_efi_fmt->efi_type     = src_efi_fmt_64->efi_type;
+               dst_efi_fmt->efi_size     = src_efi_fmt_64->efi_size;
+               dst_efi_fmt->efi_nextents = src_efi_fmt_64->efi_nextents;
+               dst_efi_fmt->efi_id       = src_efi_fmt_64->efi_id;
+               for (i = 0; i < dst_efi_fmt->efi_nextents; i++) {
+                       dst_efi_fmt->efi_extents[i].ext_start =
+                               src_efi_fmt_64->efi_extents[i].ext_start;
+                       dst_efi_fmt->efi_extents[i].ext_len =
+                               src_efi_fmt_64->efi_extents[i].ext_len;
+               }
+               return 0;
+       }
+       return EFSCORRUPTED;
+}
+
 /*
  * This is called by the efd item code below to release references to
  * the given efi item.  Each efd calls this with the number of
index 5bf681708fec915348cf0324b9392c81fa7f0287..0ea45edaab033b31ba258b2cc39c3f48634f0d70 100644 (file)
@@ -26,6 +26,24 @@ typedef struct xfs_extent {
        xfs_extlen_t    ext_len;
 } xfs_extent_t;
 
+/*
+ * Since an xfs_extent_t has types (start:64, len: 32)
+ * there are different alignments on 32 bit and 64 bit kernels.
+ * So we provide the different variants for use by a
+ * conversion routine.
+ */
+
+typedef struct xfs_extent_32 {
+       xfs_dfsbno_t    ext_start;
+       xfs_extlen_t    ext_len;
+} __attribute__((packed)) xfs_extent_32_t;
+
+typedef struct xfs_extent_64 {
+       xfs_dfsbno_t    ext_start;
+       xfs_extlen_t    ext_len;
+       __uint32_t      ext_pad;
+} xfs_extent_64_t;
+
 /*
  * This is the structure used to lay out an efi log item in the
  * log.  The efi_extents field is a variable size array whose
@@ -39,6 +57,22 @@ typedef struct xfs_efi_log_format {
        xfs_extent_t            efi_extents[1]; /* array of extents to free */
 } xfs_efi_log_format_t;
 
+typedef struct xfs_efi_log_format_32 {
+       unsigned short          efi_type;       /* efi log item type */
+       unsigned short          efi_size;       /* size of this item */
+       uint                    efi_nextents;   /* # extents to free */
+       __uint64_t              efi_id;         /* efi identifier */
+       xfs_extent_32_t         efi_extents[1]; /* array of extents to free */
+} __attribute__((packed)) xfs_efi_log_format_32_t;
+
+typedef struct xfs_efi_log_format_64 {
+       unsigned short          efi_type;       /* efi log item type */
+       unsigned short          efi_size;       /* size of this item */
+       uint                    efi_nextents;   /* # extents to free */
+       __uint64_t              efi_id;         /* efi identifier */
+       xfs_extent_64_t         efi_extents[1]; /* array of extents to free */
+} xfs_efi_log_format_64_t;
+
 /*
  * This is the structure used to lay out an efd log item in the
  * log.  The efd_extents array is a variable size array whose
@@ -52,6 +86,22 @@ typedef struct xfs_efd_log_format {
        xfs_extent_t            efd_extents[1]; /* array of extents freed */
 } xfs_efd_log_format_t;
 
+typedef struct xfs_efd_log_format_32 {
+       unsigned short          efd_type;       /* efd log item type */
+       unsigned short          efd_size;       /* size of this item */
+       uint                    efd_nextents;   /* # of extents freed */
+       __uint64_t              efd_efi_id;     /* id of corresponding efi */
+       xfs_extent_32_t         efd_extents[1]; /* array of extents freed */
+} __attribute__((packed)) xfs_efd_log_format_32_t;
+
+typedef struct xfs_efd_log_format_64 {
+       unsigned short          efd_type;       /* efd log item type */
+       unsigned short          efd_size;       /* size of this item */
+       uint                    efd_nextents;   /* # of extents freed */
+       __uint64_t              efd_efi_id;     /* id of corresponding efi */
+       xfs_extent_64_t         efd_extents[1]; /* array of extents freed */
+} xfs_efd_log_format_64_t;
+
 
 #ifdef __KERNEL__
 
@@ -103,7 +153,8 @@ extern struct kmem_zone     *xfs_efd_zone;
 xfs_efi_log_item_t     *xfs_efi_init(struct xfs_mount *, uint);
 xfs_efd_log_item_t     *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *,
                                      uint);
-
+int                    xfs_efi_copy_format(xfs_log_iovec_t *buf,
+                                           xfs_efi_log_format_t *dst_efi_fmt);
 void                   xfs_efi_item_free(xfs_efi_log_item_t *);
 
 #endif /* __KERNEL__ */
index 14010f1fa82ffe9c2f85f84290bac1236c21fd2e..0f0ad1535951c8b137278d5bf4c994910adfa8bf 100644 (file)
@@ -67,14 +67,15 @@ struct fsxattr {
 #define XFS_XFLAG_NOSYMLINKS   0x00000400      /* disallow symlink creation */
 #define XFS_XFLAG_EXTSIZE      0x00000800      /* extent size allocator hint */
 #define XFS_XFLAG_EXTSZINHERIT 0x00001000      /* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG     0x00002000      /* do not defragment */
 #define XFS_XFLAG_HASATTR      0x80000000      /* no DIFLAG for this   */
 
 /*
  * Structure for XFS_IOC_GETBMAP.
  * On input, fill in bmv_offset and bmv_length of the first structure
- * to indicate the area of interest in the file, and bmv_entry with the
- * number of array elements given.  The first structure is updated on
- * return to give the offset and length for the next call.
+ * to indicate the area of interest in the file, and bmv_entries with
+ * the number of array elements given back.  The first structure is
+ * updated on return to give the offset and length for the next call.
  */
 #ifndef HAVE_GETBMAP
 struct getbmap {
index dfa3527b20a78fd07db80df71f3ed2cbef9c7204..077629bab532eca4cd147b8d2a1f0cd4a6ceba44 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -542,14 +540,13 @@ xfs_reserve_blocks(
 }
 
 void
-xfs_fs_log_dummy(xfs_mount_t *mp)
+xfs_fs_log_dummy(
+       xfs_mount_t     *mp)
 {
-       xfs_trans_t *tp;
-       xfs_inode_t *ip;
-
+       xfs_trans_t     *tp;
+       xfs_inode_t     *ip;
 
        tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1);
-       atomic_inc(&mp->m_active_trans);
        if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) {
                xfs_trans_cancel(tp, 0);
                return;
@@ -574,21 +571,22 @@ xfs_fs_goingdown(
 {
        switch (inflags) {
        case XFS_FSOP_GOING_FLAGS_DEFAULT: {
-               struct vfs *vfsp = XFS_MTOVFS(mp);
+               struct bhv_vfs *vfsp = XFS_MTOVFS(mp);
                struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev);
 
                if (sb && !IS_ERR(sb)) {
-                       xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
+                       xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
                        thaw_bdev(sb->s_bdev, sb);
                }
        
                break;
        }
        case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
-               xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
+               xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
                break;
        case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
-               xfs_force_shutdown(mp, XFS_FORCE_UMOUNT|XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp,
+                               SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
                break;
        default:
                return XFS_ERROR(EINVAL);
index deddbd03c1667e61b6f28e12e012e5c2bd1724e3..33164a85aa9df4c3912a31157c9b8eddc5991f0c 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -1174,6 +1172,9 @@ xfs_dilocate(
        if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
            ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
 #ifdef DEBUG
+               /* no diagnostics for bulkstat, ino comes from userspace */
+               if (flags & XFS_IMAP_BULKSTAT)
+                       return XFS_ERROR(EINVAL);
                if (agno >= mp->m_sb.sb_agcount) {
                        xfs_fs_cmn_err(CE_ALERT, mp,
                                        "xfs_dilocate: agno (%d) >= "
index 60c65683462d9b1004a9245fbc802a8d5dcb0277..616eeeb6953eb27e796102c7c0aa9b23092268a1 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
index b53854325266efb6e55f46cc26f0f6de0d481ce2..0724df7fabb755fea973ca3ac87176b4e4c24e93 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -186,7 +184,7 @@ xfs_ihash_promote(
  */
 STATIC int
 xfs_iget_core(
-       vnode_t         *vp,
+       bhv_vnode_t     *vp,
        xfs_mount_t     *mp,
        xfs_trans_t     *tp,
        xfs_ino_t       ino,
@@ -198,7 +196,7 @@ xfs_iget_core(
        xfs_ihash_t     *ih;
        xfs_inode_t     *ip;
        xfs_inode_t     *iq;
-       vnode_t         *inode_vp;
+       bhv_vnode_t     *inode_vp;
        ulong           version;
        int             error;
        /* REFERENCED */
@@ -468,7 +466,7 @@ finish_inode:
         * If we have a real type for an on-disk inode, we can set ops(&unlock)
         * now.  If it's a new inode being created, xfs_ialloc will handle it.
         */
-       VFS_INIT_VNODE(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1);
+       bhv_vfs_init_vnode(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1);
 
        return 0;
 }
@@ -489,7 +487,7 @@ xfs_iget(
        xfs_daddr_t     bno)
 {
        struct inode    *inode;
-       vnode_t         *vp = NULL;
+       bhv_vnode_t     *vp = NULL;
        int             error;
 
        XFS_STATS_INC(xs_ig_attempts);
@@ -543,7 +541,7 @@ retry:
 void
 xfs_inode_lock_init(
        xfs_inode_t     *ip,
-       vnode_t         *vp)
+       bhv_vnode_t     *vp)
 {
        mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
                     "xfsino", (long)vp->v_number);
@@ -603,12 +601,10 @@ void
 xfs_iput(xfs_inode_t   *ip,
         uint           lock_flags)
 {
-       vnode_t *vp = XFS_ITOV(ip);
+       bhv_vnode_t     *vp = XFS_ITOV(ip);
 
        vn_trace_entry(vp, "xfs_iput", (inst_t *)__return_address);
-
        xfs_iunlock(ip, lock_flags);
-
        VN_RELE(vp);
 }
 
@@ -619,7 +615,7 @@ void
 xfs_iput_new(xfs_inode_t       *ip,
             uint               lock_flags)
 {
-       vnode_t         *vp = XFS_ITOV(ip);
+       bhv_vnode_t     *vp = XFS_ITOV(ip);
        struct inode    *inode = vn_to_inode(vp);
 
        vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address);
@@ -645,7 +641,7 @@ xfs_iput_new(xfs_inode_t    *ip,
 void
 xfs_ireclaim(xfs_inode_t *ip)
 {
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        /*
         * Remove from old hash list and mount list.
@@ -1033,6 +1029,6 @@ xfs_iflock_nowait(xfs_inode_t *ip)
 void
 xfs_ifunlock(xfs_inode_t *ip)
 {
-       ASSERT(valusema(&(ip->i_flock)) <= 0);
+       ASSERT(issemalocked(&(ip->i_flock)));
        vsema(&(ip->i_flock));
 }
index 94b60dd03801ba4ef4638ab0ffe50219a0170338..5fa0adb7e1737ad0ca4451409f412d73e1b5ce2f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -256,13 +254,11 @@ xfs_itobp(
        xfs_daddr_t     bno,
        uint            imap_flags)
 {
+       xfs_imap_t      imap;
        xfs_buf_t       *bp;
        int             error;
-       xfs_imap_t      imap;
-#ifdef __KERNEL__
        int             i;
        int             ni;
-#endif
 
        if (ip->i_blkno == (xfs_daddr_t)0) {
                /*
@@ -319,7 +315,6 @@ xfs_itobp(
         */
        error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno,
                                   (int)imap.im_len, XFS_BUF_LOCK, &bp);
-
        if (error) {
 #ifdef DEBUG
                xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: "
@@ -330,17 +325,21 @@ xfs_itobp(
 #endif /* DEBUG */
                return error;
        }
-#ifdef __KERNEL__
+
        /*
         * Validate the magic number and version of every inode in the buffer
         * (if DEBUG kernel) or the first inode in the buffer, otherwise.
+        * No validation is done here in userspace (xfs_repair).
         */
-#ifdef DEBUG
+#if !defined(__KERNEL__)
+       ni = 0;
+#elif defined(DEBUG)
        ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 :
                (BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog);
-#else
+#else  /* usual case */
        ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : 1;
 #endif
+
        for (i = 0; i < ni; i++) {
                int             di_ok;
                xfs_dinode_t    *dip;
@@ -352,8 +351,11 @@ xfs_itobp(
                if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP,
                                 XFS_RANDOM_ITOBP_INOTOBP))) {
 #ifdef DEBUG
-                       prdev("bad inode magic/vsn daddr %lld #%d (magic=%x)",
-                               mp->m_ddev_targp,
+                       if (!(imap_flags & XFS_IMAP_BULKSTAT))
+                               cmn_err(CE_ALERT,
+                                       "Device %s - bad inode magic/vsn "
+                                       "daddr %lld #%d (magic=%x)",
+                               XFS_BUFTARG_NAME(mp->m_ddev_targp),
                                (unsigned long long)imap.im_blkno, i,
                                INT_GET(dip->di_core.di_magic, ARCH_CONVERT));
 #endif
@@ -363,7 +365,6 @@ xfs_itobp(
                        return XFS_ERROR(EFSCORRUPTED);
                }
        }
-#endif /* __KERNEL__ */
 
        xfs_inobp_check(mp, bp);
 
@@ -782,7 +783,6 @@ xfs_xlate_dinode_core(
 
 STATIC uint
 _xfs_dic2xflags(
-       xfs_dinode_core_t       *dic,
        __uint16_t              di_flags)
 {
        uint                    flags = 0;
@@ -812,6 +812,8 @@ _xfs_dic2xflags(
                        flags |= XFS_XFLAG_EXTSIZE;
                if (di_flags & XFS_DIFLAG_EXTSZINHERIT)
                        flags |= XFS_XFLAG_EXTSZINHERIT;
+               if (di_flags & XFS_DIFLAG_NODEFRAG)
+                       flags |= XFS_XFLAG_NODEFRAG;
        }
 
        return flags;
@@ -823,16 +825,16 @@ xfs_ip2xflags(
 {
        xfs_dinode_core_t       *dic = &ip->i_d;
 
-       return _xfs_dic2xflags(dic, dic->di_flags) |
-               (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0);
+       return _xfs_dic2xflags(dic->di_flags) |
+                               (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0);
 }
 
 uint
 xfs_dic2xflags(
        xfs_dinode_core_t       *dic)
 {
-       return _xfs_dic2xflags(dic, INT_GET(dic->di_flags, ARCH_CONVERT)) |
-               (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0);
+       return _xfs_dic2xflags(INT_GET(dic->di_flags, ARCH_CONVERT)) |
+                               (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0);
 }
 
 /*
@@ -1083,7 +1085,7 @@ xfs_ialloc(
 {
        xfs_ino_t       ino;
        xfs_inode_t     *ip;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
        uint            flags;
        int             error;
 
@@ -1221,6 +1223,9 @@ xfs_ialloc(
                                di_flags |= XFS_DIFLAG_NOSYMLINKS;
                        if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
                                di_flags |= XFS_DIFLAG_PROJINHERIT;
+                       if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) &&
+                           xfs_inherit_nodefrag)
+                               di_flags |= XFS_DIFLAG_NODEFRAG;
                        ip->i_d.di_flags |= di_flags;
                }
                /* FALLTHROUGH */
@@ -1244,8 +1249,8 @@ xfs_ialloc(
         */
        xfs_trans_log_inode(tp, ip, flags);
 
-       /* now that we have an i_mode  we can set Linux inode ops (& unlock) */
-       VFS_INIT_VNODE(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1);
+       /* now that we have an i_mode we can setup inode ops and unlock */
+       bhv_vfs_init_vnode(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1);
 
        *ipp = ip;
        return 0;
@@ -1285,7 +1290,7 @@ xfs_isize_check(
                                       (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) -
                          map_first),
                         XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps,
-                        NULL))
+                        NULL, NULL))
            return;
        ASSERT(nimaps == 1);
        ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK);
@@ -1421,7 +1426,7 @@ xfs_itruncate_start(
        xfs_fsize_t     last_byte;
        xfs_off_t       toss_start;
        xfs_mount_t     *mp;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);
        ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size));
@@ -1434,9 +1439,9 @@ xfs_itruncate_start(
        vn_iowait(vp);  /* wait for the completion of any pending DIOs */
        
        /*
-        * Call VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES() to get rid of pages and buffers
+        * Call toss_pages or flushinval_pages to get rid of pages
         * overlapping the region being removed.  We have to use
-        * the less efficient VOP_FLUSHINVAL_PAGES() in the case that the
+        * the less efficient flushinval_pages in the case that the
         * caller may not be able to finish the truncate without
         * dropping the inode's I/O lock.  Make sure
         * to catch any pages brought in by buffers overlapping
@@ -1445,10 +1450,10 @@ xfs_itruncate_start(
         * so that we don't toss things on the same block as
         * new_size but before it.
         *
-        * Before calling VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES(), make sure to
+        * Before calling toss_page or flushinval_pages, make sure to
         * call remapf() over the same region if the file is mapped.
         * This frees up mapped file references to the pages in the
-        * given range and for the VOP_FLUSHINVAL_PAGES() case it ensures
+        * given range and for the flushinval_pages case it ensures
         * that we get the latest mapped changes flushed out.
         */
        toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
@@ -1466,9 +1471,9 @@ xfs_itruncate_start(
                         last_byte);
        if (last_byte > toss_start) {
                if (flags & XFS_ITRUNC_DEFINITE) {
-                       VOP_TOSS_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED);
+                       bhv_vop_toss_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
                } else {
-                       VOP_FLUSHINVAL_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED);
+                       bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
                }
        }
 
@@ -1666,12 +1671,13 @@ xfs_itruncate_finish(
                 * runs.
                 */
                XFS_BMAP_INIT(&free_list, &first_block);
-               error = xfs_bunmapi(ntp, ip, first_unmap_block,
-                                   unmap_len,
+               error = XFS_BUNMAPI(mp, ntp, &ip->i_iocore,
+                                   first_unmap_block, unmap_len,
                                    XFS_BMAPI_AFLAG(fork) |
                                      (sync ? 0 : XFS_BMAPI_ASYNC),
                                    XFS_ITRUNC_MAX_EXTENTS,
-                                   &first_block, &free_list, &done);
+                                   &first_block, &free_list,
+                                   NULL, &done);
                if (error) {
                        /*
                         * If the bunmapi call encounters an error,
@@ -2745,13 +2751,14 @@ xfs_iunpin(
                 * the inode to become unpinned.
                 */
                if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) {
-                       vnode_t *vp = XFS_ITOV_NULL(ip);
+                       bhv_vnode_t     *vp = XFS_ITOV_NULL(ip);
 
                        /* make sync come back and flush this inode */
                        if (vp) {
                                struct inode    *inode = vn_to_inode(vp);
 
-                               if (!(inode->i_state & I_NEW))
+                               if (!(inode->i_state &
+                                               (I_NEW|I_FREEING|I_CLEAR)))
                                        mark_inode_dirty_sync(inode);
                        }
                }
@@ -2916,13 +2923,6 @@ xfs_iflush_fork(
                        ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
                        memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
                }
-               if (whichfork == XFS_DATA_FORK) {
-                       if (unlikely(XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip))) {
-                               XFS_ERROR_REPORT("xfs_iflush_fork",
-                                                XFS_ERRLEVEL_LOW, mp);
-                               return XFS_ERROR(EFSCORRUPTED);
-                       }
-               }
                break;
 
        case XFS_DINODE_FMT_EXTENTS:
@@ -3006,7 +3006,7 @@ xfs_iflush(
        XFS_STATS_INC(xs_iflush_count);
 
        ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS));
-       ASSERT(valusema(&ip->i_flock) <= 0);
+       ASSERT(issemalocked(&(ip->i_flock)));
        ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
               ip->i_d.di_nextents > ip->i_df.if_ext_max);
 
@@ -3199,7 +3199,7 @@ xfs_iflush(
 
 corrupt_out:
        xfs_buf_relse(bp);
-       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
        xfs_iflush_abort(ip);
        /*
         * Unlocks the flush lock
@@ -3221,7 +3221,7 @@ cluster_corrupt_out:
                xfs_buf_relse(bp);
        }
 
-       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 
        if(!bufwasdelwri)  {
                /*
@@ -3264,7 +3264,7 @@ xfs_iflush_int(
        SPLDECL(s);
 
        ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS));
-       ASSERT(valusema(&ip->i_flock) <= 0);
+       ASSERT(issemalocked(&(ip->i_flock)));
        ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
               ip->i_d.di_nextents > ip->i_df.if_ext_max);
 
@@ -3504,7 +3504,7 @@ xfs_iflush_all(
        xfs_mount_t     *mp)
 {
        xfs_inode_t     *ip;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
  again:
        XFS_MOUNT_ILOCK(mp);
@@ -4180,7 +4180,7 @@ xfs_iext_direct_to_inline(
         */
        memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
                nextents * sizeof(xfs_bmbt_rec_t));
-       kmem_free(ifp->if_u1.if_extents, KM_SLEEP);
+       kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes);
        ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
        ifp->if_real_bytes = 0;
 }
index 3b544db1790b1508d87e8db827d908fe8a7cd318..d10b76ed1e5bd0c6f99689998f5a342a12939bad 100644 (file)
@@ -102,9 +102,9 @@ typedef struct xfs_ifork {
 
 #ifdef __KERNEL__
 struct bhv_desc;
+struct bhv_vnode;
 struct cred;
 struct ktrace;
-struct vnode;
 struct xfs_buf;
 struct xfs_bmap_free;
 struct xfs_bmbt_irec;
@@ -400,7 +400,7 @@ void                xfs_chash_init(struct xfs_mount *);
 void           xfs_chash_free(struct xfs_mount *);
 xfs_inode_t    *xfs_inode_incore(struct xfs_mount *, xfs_ino_t,
                                  struct xfs_trans *);
-void            xfs_inode_lock_init(xfs_inode_t *, struct vnode *);
+void            xfs_inode_lock_init(xfs_inode_t *, struct bhv_vnode *);
 int            xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
                         uint, uint, xfs_inode_t **, xfs_daddr_t);
 void           xfs_iput(xfs_inode_t *, uint);
@@ -461,7 +461,7 @@ void                xfs_ichgtime(xfs_inode_t *, int);
 xfs_fsize_t    xfs_file_last_byte(xfs_inode_t *);
 void           xfs_lock_inodes(xfs_inode_t **, int, int, uint);
 
-xfs_inode_t    *xfs_vtoi(struct vnode *vp);
+xfs_inode_t    *xfs_vtoi(struct bhv_vnode *vp);
 
 void           xfs_synchronize_atime(xfs_inode_t *);
 
@@ -509,7 +509,6 @@ extern struct kmem_zone     *xfs_chashlist_zone;
 extern struct kmem_zone        *xfs_ifork_zone;
 extern struct kmem_zone        *xfs_inode_zone;
 extern struct kmem_zone        *xfs_ili_zone;
-extern struct vnodeops xfs_vnodeops;
 
 #endif /* __KERNEL__ */
 
index 7497a481b2f531ed6201ecd5d4ac5ae4eabe364d..f8e80d8e72370ff12bfa66686256b7641f7ca7cc 100644 (file)
@@ -25,7 +25,6 @@
 #include "xfs_buf_item.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -33,7 +32,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -794,7 +792,7 @@ xfs_inode_item_pushbuf(
         * inode flush completed and the inode was taken off the AIL.
         * So, just get out.
         */
-       if ((valusema(&(ip->i_flock)) > 0)  ||
+       if (!issemalocked(&(ip->i_flock)) ||
            ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) {
                iip->ili_pushbuf_flag = 0;
                xfs_iunlock(ip, XFS_ILOCK_SHARED);
@@ -816,7 +814,7 @@ xfs_inode_item_pushbuf(
                         * If not, we can flush it async.
                         */
                        dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) &&
-                                 (valusema(&(ip->i_flock)) <= 0));
+                                 issemalocked(&(ip->i_flock)));
                        iip->ili_pushbuf_flag = 0;
                        xfs_iunlock(ip, XFS_ILOCK_SHARED);
                        xfs_buftrace("INODE ITEM PUSH", bp);
@@ -864,7 +862,7 @@ xfs_inode_item_push(
        ip = iip->ili_inode;
 
        ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS));
-       ASSERT(valusema(&(ip->i_flock)) <= 0);
+       ASSERT(issemalocked(&(ip->i_flock)));
        /*
         * Since we were able to lock the inode's flush lock and
         * we found it on the AIL, the inode must be dirty.  This
@@ -1084,3 +1082,52 @@ xfs_istale_done(
 {
        xfs_iflush_abort(iip->ili_inode);
 }
+
+/*
+ * convert an xfs_inode_log_format struct from either 32 or 64 bit versions
+ * (which can have different field alignments) to the native version
+ */
+int
+xfs_inode_item_format_convert(
+       xfs_log_iovec_t         *buf,
+       xfs_inode_log_format_t  *in_f)
+{
+       if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) {
+               xfs_inode_log_format_32_t *in_f32;
+
+               in_f32 = (xfs_inode_log_format_32_t *)buf->i_addr;
+               in_f->ilf_type = in_f32->ilf_type;
+               in_f->ilf_size = in_f32->ilf_size;
+               in_f->ilf_fields = in_f32->ilf_fields;
+               in_f->ilf_asize = in_f32->ilf_asize;
+               in_f->ilf_dsize = in_f32->ilf_dsize;
+               in_f->ilf_ino = in_f32->ilf_ino;
+               /* copy biggest field of ilf_u */
+               memcpy(in_f->ilf_u.ilfu_uuid.__u_bits,
+                      in_f32->ilf_u.ilfu_uuid.__u_bits,
+                      sizeof(uuid_t));
+               in_f->ilf_blkno = in_f32->ilf_blkno;
+               in_f->ilf_len = in_f32->ilf_len;
+               in_f->ilf_boffset = in_f32->ilf_boffset;
+               return 0;
+       } else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){
+               xfs_inode_log_format_64_t *in_f64;
+
+               in_f64 = (xfs_inode_log_format_64_t *)buf->i_addr;
+               in_f->ilf_type = in_f64->ilf_type;
+               in_f->ilf_size = in_f64->ilf_size;
+               in_f->ilf_fields = in_f64->ilf_fields;
+               in_f->ilf_asize = in_f64->ilf_asize;
+               in_f->ilf_dsize = in_f64->ilf_dsize;
+               in_f->ilf_ino = in_f64->ilf_ino;
+               /* copy biggest field of ilf_u */
+               memcpy(in_f->ilf_u.ilfu_uuid.__u_bits,
+                      in_f64->ilf_u.ilfu_uuid.__u_bits,
+                      sizeof(uuid_t));
+               in_f->ilf_blkno = in_f64->ilf_blkno;
+               in_f->ilf_len = in_f64->ilf_len;
+               in_f->ilf_boffset = in_f64->ilf_boffset;
+               return 0;
+       }
+       return EFSCORRUPTED;
+}
index c5dbf93b6661bf71c735954d1322d2caacfcb757..5db6cd1b4cf3278fec78975c7969492f96d67dde 100644 (file)
  * log.  The size of the inline data/extents/b-tree root to be logged
  * (if any) is indicated in the ilf_dsize field.  Changes to this structure
  * must be added on to the end.
- *
- * Convention for naming inode log item versions :  The current version
- * is always named XFS_LI_INODE.  When an inode log item gets superseded,
- * add the latest version of IRIX that will generate logs with that item
- * to the version name.
- *
- * -Version 1 of this structure (XFS_LI_5_3_INODE) included up to the first
- *     union (ilf_u) field.  This was released with IRIX 5.3-XFS.
- * -Version 2 of this structure (XFS_LI_6_1_INODE) is currently the entire
- *     structure.  This was released with IRIX 6.0.1-XFS and IRIX 6.1.
- * -Version 3 of this structure (XFS_LI_INODE) is the same as version 2
- *     so a new structure definition wasn't necessary.  However, we had
- *     to add a new type because the inode cluster size changed from 4K
- *     to 8K and the version number had to be rev'ved to keep older kernels
- *     from trying to recover logs with the 8K buffers in them.  The logging
- *     code can handle recovery on different-sized clusters now so hopefully
- *     this'll be the last time we need to change the inode log item just
- *     for a change in the inode cluster size.  This new version was
- *     released with IRIX 6.2.
  */
 typedef struct xfs_inode_log_format {
        unsigned short          ilf_type;       /* inode log item type */
@@ -59,18 +40,38 @@ typedef struct xfs_inode_log_format {
        int                     ilf_boffset;    /* off of inode in buffer */
 } xfs_inode_log_format_t;
 
-/* Initial version shipped with IRIX 5.3-XFS */
-typedef struct xfs_inode_log_format_v1 {
-       unsigned short          ilf_type;       /* inode log item type */
-       unsigned short          ilf_size;       /* size of this item */
-       uint                    ilf_fields;     /* flags for fields logged */
-       uint                    ilf_dsize;      /* size of data/ext/root */
-       xfs_ino_t               ilf_ino;        /* inode number */
+typedef struct xfs_inode_log_format_32 {
+       unsigned short          ilf_type;       /* 16: inode log item type */
+       unsigned short          ilf_size;       /* 16: size of this item */
+       uint                    ilf_fields;     /* 32: flags for fields logged */
+       ushort                  ilf_asize;      /* 32: size of attr d/ext/root */
+       ushort                  ilf_dsize;      /* 32: size of data/ext/root */
+       xfs_ino_t               ilf_ino;        /* 64: inode number */
        union {
-               xfs_dev_t       ilfu_rdev;      /* rdev value for dev inode*/
-               uuid_t          ilfu_uuid;      /* mount point value */
+               xfs_dev_t       ilfu_rdev;      /* 32: rdev value for dev inode*/
+               uuid_t          ilfu_uuid;      /* 128: mount point value */
+       } ilf_u;
+       __int64_t               ilf_blkno;      /* 64: blkno of inode buffer */
+       int                     ilf_len;        /* 32: len of inode buffer */
+       int                     ilf_boffset;    /* 32: off of inode in buffer */
+} __attribute__((packed)) xfs_inode_log_format_32_t;
+
+typedef struct xfs_inode_log_format_64 {
+       unsigned short          ilf_type;       /* 16: inode log item type */
+       unsigned short          ilf_size;       /* 16: size of this item */
+       uint                    ilf_fields;     /* 32: flags for fields logged */
+       ushort                  ilf_asize;      /* 32: size of attr d/ext/root */
+       ushort                  ilf_dsize;      /* 32: size of data/ext/root */
+       __uint32_t              ilf_pad;        /* 32: pad for 64 bit boundary */
+       xfs_ino_t               ilf_ino;        /* 64: inode number */
+       union {
+               xfs_dev_t       ilfu_rdev;      /* 32: rdev value for dev inode*/
+               uuid_t          ilfu_uuid;      /* 128: mount point value */
        } ilf_u;
-} xfs_inode_log_format_t_v1;
+       __int64_t               ilf_blkno;      /* 64: blkno of inode buffer */
+       int                     ilf_len;        /* 32: len of inode buffer */
+       int                     ilf_boffset;    /* 32: off of inode in buffer */
+} xfs_inode_log_format_64_t;
 
 /*
  * Flags for xfs_trans_log_inode flags field.
@@ -172,6 +173,8 @@ extern void xfs_inode_item_destroy(struct xfs_inode *);
 extern void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *);
 extern void xfs_istale_done(struct xfs_buf *, xfs_inode_log_item_t *);
 extern void xfs_iflush_abort(struct xfs_inode *);
+extern int xfs_inode_item_format_convert(xfs_log_iovec_t *,
+                                        xfs_inode_log_format_t *);
 
 #endif /* __KERNEL__ */
 
index a07815661a8ce0063be641e7a6367841f087ec9e..06d710c9ce4b5dec4c9f4b72cadde1d5aa39c07a 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
+#include "xfs_dfrag.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -58,7 +57,7 @@ xfs_size_fn(
 
 STATIC int
 xfs_ioinit(
-       struct vfs              *vfsp,
+       struct bhv_vfs          *vfsp,
        struct xfs_mount_args   *mntargs,
        int                     flags)
 {
@@ -68,6 +67,7 @@ xfs_ioinit(
 xfs_ioops_t    xfs_iocore_xfs = {
        .xfs_ioinit             = (xfs_ioinit_t) xfs_ioinit,
        .xfs_bmapi_func         = (xfs_bmapi_t) xfs_bmapi,
+       .xfs_bunmapi_func       = (xfs_bunmapi_t) xfs_bunmapi,
        .xfs_bmap_eof_func      = (xfs_bmap_eof_t) xfs_bmap_eof,
        .xfs_iomap_write_direct =
                        (xfs_iomap_write_direct_t) xfs_iomap_write_direct,
@@ -84,6 +84,7 @@ xfs_ioops_t   xfs_iocore_xfs = {
        .xfs_unlock             = (xfs_unlk_t) xfs_iunlock,
        .xfs_size_func          = (xfs_size_t) xfs_size_fn,
        .xfs_iodone             = (xfs_iodone_t) fs_noerr,
+       .xfs_swap_extents_func  = (xfs_swap_extents_t) xfs_swap_extents,
 };
 
 void
index d5dfedcb8922a2b506b772f65ff1e5d1cd848f80..f1949c16df154157bbdada2882d2656ab918311f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_dmapi.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -252,7 +250,7 @@ xfs_iomap(
        error = XFS_BMAPI(mp, NULL, io, offset_fsb,
                        (xfs_filblks_t)(end_fsb - offset_fsb),
                        bmapi_flags,  NULL, 0, &imap,
-                       &nimaps, NULL);
+                       &nimaps, NULL, NULL);
 
        if (error)
                goto out;
@@ -519,8 +517,8 @@ xfs_iomap_write_direct(
         */
        XFS_BMAP_INIT(&free_list, &firstfsb);
        nimaps = 1;
-       error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
-               bmapi_flag, &firstfsb, 0, &imap, &nimaps, &free_list);
+       error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, bmapi_flag,
+               &firstfsb, 0, &imap, &nimaps, &free_list, NULL);
        if (error)
                goto error0;
 
@@ -610,8 +608,8 @@ xfs_iomap_eof_want_preallocate(
        while (count_fsb > 0) {
                imaps = nimaps;
                firstblock = NULLFSBLOCK;
-               error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb,
-                                 0, &firstblock, 0, imap, &imaps, NULL);
+               error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, 0,
+                                 &firstblock, 0, imap, &imaps, NULL, NULL);
                if (error)
                        return error;
                for (n = 0; n < imaps; n++) {
@@ -695,11 +693,11 @@ retry:
 
        nimaps = XFS_WRITE_IMAPS;
        firstblock = NULLFSBLOCK;
-       error = xfs_bmapi(NULL, ip, offset_fsb,
+       error = XFS_BMAPI(mp, NULL, io, offset_fsb,
                          (xfs_filblks_t)(last_fsb - offset_fsb),
                          XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
                          XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
-                         &nimaps, NULL);
+                         &nimaps, NULL, NULL);
        if (error && (error != ENOSPC))
                return XFS_ERROR(error);
 
@@ -832,9 +830,9 @@ xfs_iomap_write_allocate(
                        }
 
                        /* Go get the actual blocks */
-                       error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb,
+                       error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb,
                                        XFS_BMAPI_WRITE, &first_block, 1,
-                                       imap, &nimaps, &free_list);
+                                       imap, &nimaps, &free_list, NULL);
                        if (error)
                                goto trans_cancel;
 
@@ -955,9 +953,9 @@ xfs_iomap_write_unwritten(
                 */
                XFS_BMAP_INIT(&free_list, &firstfsb);
                nimaps = 1;
-               error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,
+               error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb,
                                  XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb,
-                                 1, &imap, &nimaps, &free_list);
+                                 1, &imap, &nimaps, &free_list, NULL);
                if (error)
                        goto error_on_bmapi_transaction;
 
index 94068d014f27fb19d43392017f716c2151dfdf87..46249e4d1feaba62eec485e23376c2d3508f7440 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_error.h"
 #include "xfs_btree.h"
 
-#ifndef HAVE_USERACC
-#define useracc(ubuffer, size, flags, foo) (0)
-#define unuseracc(ubuffer, size, flags)
-#endif
-
 STATIC int
 xfs_bulkstat_one_iget(
        xfs_mount_t     *mp,            /* mount point for filesystem */
@@ -56,7 +49,7 @@ xfs_bulkstat_one_iget(
 {
        xfs_dinode_core_t *dic;         /* dinode core info pointer */
        xfs_inode_t     *ip;            /* incore inode pointer */
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
        int             error;
 
        error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno);
@@ -335,15 +328,6 @@ xfs_bulkstat(
                (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);
        nimask = ~(nicluster - 1);
        nbcluster = nicluster >> mp->m_sb.sb_inopblog;
-       /*
-        * Lock down the user's buffer. If a buffer was not sent, as in the case
-        * disk quota code calls here, we skip this.
-        */
-       if (ubuffer &&
-           (error = useracc(ubuffer, ubcount * statstruct_size,
-                       (B_READ|B_PHYS), NULL))) {
-               return error;
-       }
        /*
         * Allocate a page-sized buffer for inode btree records.
         * We could try allocating something smaller, but for normal
@@ -650,8 +634,6 @@ xfs_bulkstat(
         * Done, we're either out of filesystem or space to put the data.
         */
        kmem_free(irbuf, NBPC);
-       if (ubuffer)
-               unuseracc(ubuffer, ubcount * statstruct_size, (B_READ|B_PHYS));
        *ubcountp = ubelem;
        if (agno >= mp->m_sb.sb_agcount) {
                /*
index 11eb4e1b18c46fc08103bb881816ec6575c6bd8d..be5f12e07d2217d98814127747d8fc9eadb40cc0 100644 (file)
@@ -45,7 +45,6 @@ typedef int (*bulkstat_one_pf)(struct xfs_mount       *mp,
  */
 #define        BULKSTAT_FG_IGET        0x1     /* Go through the buffer cache */
 #define        BULKSTAT_FG_QUICK       0x2     /* No iget, walk the dinode cluster */
-#define BULKSTAT_FG_VFSLOCKED  0x4     /* Already have vfs lock */
 
 /*
  * Return stat information in bulk (by-inode) for the filesystem.
index 32e841d2f26db647a0a73469ec61dfaba4b2ccc8..d8f5d4cbe8b7b7819bb403e225389c54c22fd8b5 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -36,7 +35,6 @@
 #include "xfs_ialloc_btree.h"
 #include "xfs_log_recover.h"
 #include "xfs_trans_priv.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -402,7 +400,7 @@ xfs_log_release_iclog(xfs_mount_t *mp,
        xlog_in_core_t    *iclog = (xlog_in_core_t *)iclog_hndl;
 
        if (xlog_state_release_iclog(log, iclog)) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
                return EIO;
        }
 
@@ -498,9 +496,8 @@ xfs_log_mount(xfs_mount_t   *mp,
         * just worked.
         */
        if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) {
-               int     error;
-               vfs_t   *vfsp = XFS_MTOVFS(mp);
-               int     readonly = (vfsp->vfs_flag & VFS_RDONLY);
+               bhv_vfs_t       *vfsp = XFS_MTOVFS(mp);
+               int             error, readonly = (vfsp->vfs_flag & VFS_RDONLY);
 
                if (readonly)
                        vfsp->vfs_flag &= ~VFS_RDONLY;
@@ -726,7 +723,7 @@ xfs_log_write(xfs_mount_t * mp,
                return XFS_ERROR(EIO);
 
        if ((error = xlog_write(mp, reg, nentries, tic, start_lsn, NULL, 0))) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
        }
        return error;
 }      /* xfs_log_write */
@@ -816,9 +813,9 @@ xfs_log_need_covered(xfs_mount_t *mp)
        SPLDECL(s);
        int             needed = 0, gen;
        xlog_t          *log = mp->m_log;
-       vfs_t           *vfsp = XFS_MTOVFS(mp);
+       bhv_vfs_t       *vfsp = XFS_MTOVFS(mp);
 
-       if (fs_frozen(vfsp) || XFS_FORCED_SHUTDOWN(mp) ||
+       if (vfs_test_for_freeze(vfsp) || XFS_FORCED_SHUTDOWN(mp) ||
            (vfsp->vfs_flag & VFS_RDONLY))
                return 0;
 
@@ -956,7 +953,7 @@ xlog_iodone(xfs_buf_t *bp)
                        XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
                xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp));
                XFS_BUF_STALE(bp);
-               xfs_force_shutdown(l->l_mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(l->l_mp, SHUTDOWN_LOG_IO_ERROR);
                /*
                 * This flag will be propagated to the trans-committed
                 * callback routines to let them know that the log-commit
@@ -1261,7 +1258,7 @@ xlog_commit_record(xfs_mount_t  *mp,
        ASSERT_ALWAYS(iclog);
        if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp,
                               iclog, XLOG_COMMIT_TRANS))) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
        }
        return error;
 }      /* xlog_commit_record */
@@ -1790,7 +1787,7 @@ xlog_write(xfs_mount_t *  mp,
        xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp,
                "xfs_log_write: reservation ran out. Need to up reservation");
        /* If we did not panic, shutdown the filesystem */
-       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 #endif
     } else
        ticket->t_curr_res -= len;
index 1f0016b0b4ec2a211d3d19dd15740b5058ebb894..55b4237c2153975e00ded0b662dcf36edd861ca2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -193,14 +191,14 @@ xlog_header_check_dump(
 {
        int                     b;
 
-       printk("%s:  SB : uuid = ", __FUNCTION__);
+       cmn_err(CE_DEBUG, "%s:  SB : uuid = ", __FUNCTION__);
        for (b = 0; b < 16; b++)
-               printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]);
-       printk(", fmt = %d\n", XLOG_FMT);
-       printk("    log : uuid = ");
+               cmn_err(CE_DEBUG, "%02x", ((uchar_t *)&mp->m_sb.sb_uuid)[b]);
+       cmn_err(CE_DEBUG, ", fmt = %d\n", XLOG_FMT);
+       cmn_err(CE_DEBUG, "    log : uuid = ");
        for (b = 0; b < 16; b++)
-               printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]);
-       printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));
+               cmn_err(CE_DEBUG, "%02x",((uchar_t *)&head->h_fs_uuid)[b]);
+       cmn_err(CE_DEBUG, ", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));
 }
 #else
 #define xlog_header_check_dump(mp, head)
@@ -282,7 +280,7 @@ xlog_recover_iodone(
                mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *);
                xfs_ioerror_alert("xlog_recover_iodone",
                                  mp, bp, XFS_BUF_ADDR(bp));
-               xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
        }
        XFS_BUF_SET_FSPRIVATE(bp, NULL);
        XFS_BUF_CLR_IODONE_FUNC(bp);
@@ -1889,7 +1887,7 @@ xlog_recover_do_inode_buffer(
 
                buffer_nextp = (xfs_agino_t *)xfs_buf_offset(bp,
                                              next_unlinked_offset);
-               INT_SET(*buffer_nextp, ARCH_CONVERT, *logged_nextp);
+               *buffer_nextp = *logged_nextp;
        }
 
        return 0;
@@ -2292,12 +2290,22 @@ xlog_recover_do_inode_trans(
        int                     attr_index;
        uint                    fields;
        xfs_dinode_core_t       *dicp;
+       int                     need_free = 0;
 
        if (pass == XLOG_RECOVER_PASS1) {
                return 0;
        }
 
-       in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
+       if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) {
+               in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
+       } else {
+               in_f = (xfs_inode_log_format_t *)kmem_alloc(
+                       sizeof(xfs_inode_log_format_t), KM_SLEEP);
+               need_free = 1;
+               error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f);
+               if (error)
+                       goto error;
+       }
        ino = in_f->ilf_ino;
        mp = log->l_mp;
        if (ITEM_TYPE(item) == XFS_LI_INODE) {
@@ -2323,8 +2331,10 @@ xlog_recover_do_inode_trans(
         * Inode buffers can be freed, look out for it,
         * and do not replay the inode.
         */
-       if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0))
-               return 0;
+       if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0)) {
+               error = 0;
+               goto error;
+       }
 
        bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len,
                                                                XFS_BUF_LOCK);
@@ -2333,7 +2343,7 @@ xlog_recover_do_inode_trans(
                                  bp, imap.im_blkno);
                error = XFS_BUF_GETERROR(bp);
                xfs_buf_relse(bp);
-               return error;
+               goto error;
        }
        error = 0;
        ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
@@ -2350,7 +2360,8 @@ xlog_recover_do_inode_trans(
                        dip, bp, ino);
                XFS_ERROR_REPORT("xlog_recover_do_inode_trans(1)",
                                 XFS_ERRLEVEL_LOW, mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               error = EFSCORRUPTED;
+               goto error;
        }
        dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr);
        if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) {
@@ -2360,7 +2371,8 @@ xlog_recover_do_inode_trans(
                        item, ino);
                XFS_ERROR_REPORT("xlog_recover_do_inode_trans(2)",
                                 XFS_ERRLEVEL_LOW, mp);
-               return XFS_ERROR(EFSCORRUPTED);
+               error = EFSCORRUPTED;
+               goto error;
        }
 
        /* Skip replay when the on disk inode is newer than the log one */
@@ -2376,7 +2388,8 @@ xlog_recover_do_inode_trans(
                        /* do nothing */
                } else {
                        xfs_buf_relse(bp);
-                       return 0;
+                       error = 0;
+                       goto error;
                }
        }
        /* Take the opportunity to reset the flush iteration count */
@@ -2391,7 +2404,8 @@ xlog_recover_do_inode_trans(
                        xfs_fs_cmn_err(CE_ALERT, mp,
                                "xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                                item, dip, bp, ino);
-                       return XFS_ERROR(EFSCORRUPTED);
+                       error = EFSCORRUPTED;
+                       goto error;
                }
        } else if (unlikely((dicp->di_mode & S_IFMT) == S_IFDIR)) {
                if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
@@ -2403,7 +2417,8 @@ xlog_recover_do_inode_trans(
                        xfs_fs_cmn_err(CE_ALERT, mp,
                                "xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                                item, dip, bp, ino);
-                       return XFS_ERROR(EFSCORRUPTED);
+                       error = EFSCORRUPTED;
+                       goto error;
                }
        }
        if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){
@@ -2415,7 +2430,8 @@ xlog_recover_do_inode_trans(
                        item, dip, bp, ino,
                        dicp->di_nextents + dicp->di_anextents,
                        dicp->di_nblocks);
-               return XFS_ERROR(EFSCORRUPTED);
+               error = EFSCORRUPTED;
+               goto error;
        }
        if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) {
                XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(6)",
@@ -2424,7 +2440,8 @@ xlog_recover_do_inode_trans(
                xfs_fs_cmn_err(CE_ALERT, mp,
                        "xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x",
                        item, dip, bp, ino, dicp->di_forkoff);
-               return XFS_ERROR(EFSCORRUPTED);
+               error = EFSCORRUPTED;
+               goto error;
        }
        if (unlikely(item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t))) {
                XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(7)",
@@ -2433,7 +2450,8 @@ xlog_recover_do_inode_trans(
                xfs_fs_cmn_err(CE_ALERT, mp,
                        "xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p",
                        item->ri_buf[1].i_len, item);
-               return XFS_ERROR(EFSCORRUPTED);
+               error = EFSCORRUPTED;
+               goto error;
        }
 
        /* The core is in in-core format */
@@ -2521,7 +2539,8 @@ xlog_recover_do_inode_trans(
                        xlog_warn("XFS: xlog_recover_do_inode_trans: Invalid flag");
                        ASSERT(0);
                        xfs_buf_relse(bp);
-                       return XFS_ERROR(EIO);
+                       error = EIO;
+                       goto error;
                }
        }
 
@@ -2537,7 +2556,10 @@ write_inode_buffer:
                error = xfs_bwrite(mp, bp);
        }
 
-       return (error);
+error:
+       if (need_free)
+               kmem_free(in_f, sizeof(*in_f));
+       return XFS_ERROR(error);
 }
 
 /*
@@ -2674,32 +2696,32 @@ xlog_recover_do_dquot_trans(
  * structure into it, and adds the efi to the AIL with the given
  * LSN.
  */
-STATIC void
+STATIC int
 xlog_recover_do_efi_trans(
        xlog_t                  *log,
        xlog_recover_item_t     *item,
        xfs_lsn_t               lsn,
        int                     pass)
 {
+       int                     error;
        xfs_mount_t             *mp;
        xfs_efi_log_item_t      *efip;
        xfs_efi_log_format_t    *efi_formatp;
        SPLDECL(s);
 
        if (pass == XLOG_RECOVER_PASS1) {
-               return;
+               return 0;
        }
 
        efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr;
-       ASSERT(item->ri_buf[0].i_len ==
-              (sizeof(xfs_efi_log_format_t) +
-               ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t))));
 
        mp = log->l_mp;
        efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
-       memcpy((char *)&(efip->efi_format), (char *)efi_formatp,
-             sizeof(xfs_efi_log_format_t) +
-             ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)));
+       if ((error = xfs_efi_copy_format(&(item->ri_buf[0]),
+                                        &(efip->efi_format)))) {
+               xfs_efi_item_free(efip);
+               return error;
+       }
        efip->efi_next_extent = efi_formatp->efi_nextents;
        efip->efi_flags |= XFS_EFI_COMMITTED;
 
@@ -2708,6 +2730,7 @@ xlog_recover_do_efi_trans(
         * xfs_trans_update_ail() drops the AIL lock.
         */
        xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s);
+       return 0;
 }
 
 
@@ -2738,9 +2761,10 @@ xlog_recover_do_efd_trans(
        }
 
        efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
-       ASSERT(item->ri_buf[0].i_len ==
-              (sizeof(xfs_efd_log_format_t) +
-               ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_t))));
+       ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) +
+               ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) ||
+              (item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) +
+               ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_64_t)))));
        efi_id = efd_formatp->efd_efi_id;
 
        /*
@@ -2810,15 +2834,14 @@ xlog_recover_do_trans(
                        if  ((error = xlog_recover_do_buffer_trans(log, item,
                                                                 pass)))
                                break;
-               } else if ((ITEM_TYPE(item) == XFS_LI_INODE) ||
-                          (ITEM_TYPE(item) == XFS_LI_6_1_INODE) ||
-                          (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) {
+               } else if ((ITEM_TYPE(item) == XFS_LI_INODE)) {
                        if ((error = xlog_recover_do_inode_trans(log, item,
                                                                pass)))
                                break;
                } else if (ITEM_TYPE(item) == XFS_LI_EFI) {
-                       xlog_recover_do_efi_trans(log, item, trans->r_lsn,
-                                                 pass);
+                       if ((error = xlog_recover_do_efi_trans(log, item, trans->r_lsn,
+                                                 pass)))
+                               break;
                } else if (ITEM_TYPE(item) == XFS_LI_EFD) {
                        xlog_recover_do_efd_trans(log, item, pass);
                } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) {
@@ -3419,13 +3442,13 @@ xlog_unpack_data_checksum(
            if (rhead->h_chksum ||
                ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) {
                    cmn_err(CE_DEBUG,
-                       "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)",
+                       "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)\n",
                            INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum);
                    cmn_err(CE_DEBUG,
 "XFS: Disregard message if filesystem was created with non-DEBUG kernel");
                    if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
                            cmn_err(CE_DEBUG,
-                               "XFS: LogR this is a LogV2 filesystem");
+                               "XFS: LogR this is a LogV2 filesystem\n");
                    }
                    log->l_flags |= XLOG_CHKSUM_MISMATCH;
            }
@@ -3798,7 +3821,7 @@ xlog_do_log_recovery(
        error = xlog_do_recovery_pass(log, head_blk, tail_blk,
                                      XLOG_RECOVER_PASS2);
 #ifdef DEBUG
-       {
+       if (!error) {
                int     i;
 
                for (i = 0; i < XLOG_BC_TABLE_SIZE; i++)
@@ -3974,7 +3997,7 @@ xlog_recover_finish(
                log->l_flags &= ~XLOG_RECOVERY_NEEDED;
        } else {
                cmn_err(CE_DEBUG,
-                       "!Ending clean XFS mount for filesystem: %s",
+                       "!Ending clean XFS mount for filesystem: %s\n",
                        log->l_mp->m_fsname);
        }
        return 0;
index c0b1c2906880da1b58bcb217c4c11c407ee539d0..10dbf203c62f6f929ee709d6624121f744de231a 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -196,7 +194,7 @@ xfs_mount_free(
                kmem_free(mp->m_logname, strlen(mp->m_logname) + 1);
 
        if (remove_bhv) {
-               struct vfs      *vfsp = XFS_MTOVFS(mp);
+               struct bhv_vfs  *vfsp = XFS_MTOVFS(mp);
 
                bhv_remove_all_vfsops(vfsp, 0);
                VFS_REMOVEBHV(vfsp, &mp->m_bhv);
@@ -337,7 +335,7 @@ xfs_mount_validate_sb(
 
 xfs_agnumber_t
 xfs_initialize_perag(
-       struct vfs      *vfs,
+       bhv_vfs_t       *vfs,
        xfs_mount_t     *mp,
        xfs_agnumber_t  agcount)
 {
@@ -651,14 +649,14 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
  */
 int
 xfs_mountfs(
-       vfs_t           *vfsp,
+       bhv_vfs_t       *vfsp,
        xfs_mount_t     *mp,
        int             mfsi_flags)
 {
        xfs_buf_t       *bp;
        xfs_sb_t        *sbp = &(mp->m_sb);
        xfs_inode_t     *rip;
-       vnode_t         *rvp = NULL;
+       bhv_vnode_t     *rvp = NULL;
        int             readio_log, writeio_log;
        xfs_daddr_t     d;
        __uint64_t      ret64;
@@ -934,18 +932,7 @@ xfs_mountfs(
        vfsp->vfs_altfsid = (xfs_fsid_t *)mp->m_fixedfsid;
        mp->m_dmevmask = 0;     /* not persistent; set after each mount */
 
-       /*
-        * Select the right directory manager.
-        */
-       mp->m_dirops =
-               XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ?
-                       xfsv2_dirops :
-                       xfsv1_dirops;
-
-       /*
-        * Initialize directory manager's entries.
-        */
-       XFS_DIR_MOUNT(mp);
+       xfs_dir_mount(mp);
 
        /*
         * Initialize the attribute manager's entries.
@@ -1006,8 +993,9 @@ xfs_mountfs(
 
        if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) {
                cmn_err(CE_WARN, "XFS: corrupted root inode");
-               prdev("Root inode %llu is not a directory",
-                     mp->m_ddev_targp, (unsigned long long)rip->i_ino);
+               cmn_err(CE_WARN, "Device %s - root %llu is not a directory",
+                       XFS_BUFTARG_NAME(mp->m_ddev_targp),
+                       (unsigned long long)rip->i_ino);
                xfs_iunlock(rip, XFS_ILOCK_EXCL);
                XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
                                 mp);
@@ -1094,7 +1082,7 @@ xfs_mountfs(
 int
 xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
 {
-       struct vfs      *vfsp = XFS_MTOVFS(mp);
+       struct bhv_vfs  *vfsp = XFS_MTOVFS(mp);
 #if defined(DEBUG) || defined(INDUCE_IO_ERROR)
        int64_t         fsid;
 #endif
@@ -1254,6 +1242,26 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
 
        xfs_trans_log_buf(tp, bp, first, last);
 }
+
+/*
+ * In order to avoid ENOSPC-related deadlock caused by
+ * out-of-order locking of AGF buffer (PV 947395), we place
+ * constraints on the relationship among actual allocations for
+ * data blocks, freelist blocks, and potential file data bmap
+ * btree blocks. However, these restrictions may result in no
+ * actual space allocated for a delayed extent, for example, a data
+ * block in a certain AG is allocated but there is no additional
+ * block for the additional bmap btree block due to a split of the
+ * bmap btree of the file. The result of this may lead to an
+ * infinite loop in xfssyncd when the file gets flushed to disk and
+ * all delayed extents need to be actually allocated. To get around
+ * this, we explicitly set aside a few blocks which will not be
+ * reserved in delayed allocation. Considering the minimum number of
+ * needed freelist blocks is 4 fsbs, a potential split of file's bmap
+ * btree requires 1 fsb, so we set the number of set-aside blocks to 8.
+*/
+#define SET_ASIDE_BLOCKS 8
+
 /*
  * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply
  * a delta to a specified field in the in-core superblock.  Simply
@@ -1298,7 +1306,7 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field,
                return 0;
        case XFS_SBS_FDBLOCKS:
 
-               lcounter = (long long)mp->m_sb.sb_fdblocks;
+               lcounter = (long long)mp->m_sb.sb_fdblocks - SET_ASIDE_BLOCKS;
                res_used = (long long)(mp->m_resblks - mp->m_resblks_avail);
 
                if (delta > 0) {                /* Putting blocks back */
@@ -1332,7 +1340,7 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field,
                        }
                }
 
-               mp->m_sb.sb_fdblocks = lcounter;
+               mp->m_sb.sb_fdblocks = lcounter + SET_ASIDE_BLOCKS;
                return 0;
        case XFS_SBS_FREXTENTS:
                lcounter = (long long)mp->m_sb.sb_frextents;
index 668ad23fd37c9c5683dea0cfbfef387a0364e32c..b2bd4be4200a305d449d831e6d88edeac614380e 100644 (file)
@@ -53,8 +53,8 @@ typedef struct xfs_trans_reservations {
 #else
 struct cred;
 struct log;
-struct vfs;
-struct vnode;
+struct bhv_vfs;
+struct bhv_vnode;
 struct xfs_mount_args;
 struct xfs_ihash;
 struct xfs_chash;
@@ -63,9 +63,11 @@ struct xfs_perag;
 struct xfs_iocore;
 struct xfs_bmbt_irec;
 struct xfs_bmap_free;
+struct xfs_extdelta;
+struct xfs_swapext;
 
-extern struct vfsops xfs_vfsops;
-extern struct vnodeops xfs_vnodeops;
+extern struct bhv_vfsops xfs_vfsops;
+extern struct bhv_vnodeops xfs_vnodeops;
 
 #define        AIL_LOCK_T              lock_t
 #define        AIL_LOCKINIT(x,y)       spinlock_init(x,y)
@@ -78,15 +80,15 @@ extern struct vnodeops xfs_vnodeops;
  * Prototypes and functions for the Data Migration subsystem.
  */
 
-typedef int    (*xfs_send_data_t)(int, struct vnode *,
-                       xfs_off_t, size_t, int, vrwlock_t *);
+typedef int    (*xfs_send_data_t)(int, struct bhv_vnode *,
+                       xfs_off_t, size_t, int, bhv_vrwlock_t *);
 typedef int    (*xfs_send_mmap_t)(struct vm_area_struct *, uint);
-typedef int    (*xfs_send_destroy_t)(struct vnode *, dm_right_t);
-typedef int    (*xfs_send_namesp_t)(dm_eventtype_t, struct vfs *,
-                       struct vnode *,
-                       dm_right_t, struct vnode *, dm_right_t,
+typedef int    (*xfs_send_destroy_t)(struct bhv_vnode *, dm_right_t);
+typedef int    (*xfs_send_namesp_t)(dm_eventtype_t, struct bhv_vfs *,
+                       struct bhv_vnode *,
+                       dm_right_t, struct bhv_vnode *, dm_right_t,
                        char *, char *, mode_t, int, int);
-typedef void   (*xfs_send_unmount_t)(struct vfs *, struct vnode *,
+typedef void   (*xfs_send_unmount_t)(struct bhv_vfs *, struct bhv_vnode *,
                        dm_right_t, mode_t, int, int);
 
 typedef struct xfs_dmops {
@@ -188,13 +190,18 @@ typedef struct xfs_qmops {
  * Prototypes and functions for I/O core modularization.
  */
 
-typedef int            (*xfs_ioinit_t)(struct vfs *,
+typedef int            (*xfs_ioinit_t)(struct bhv_vfs *,
                                struct xfs_mount_args *, int);
 typedef int            (*xfs_bmapi_t)(struct xfs_trans *, void *,
                                xfs_fileoff_t, xfs_filblks_t, int,
                                xfs_fsblock_t *, xfs_extlen_t,
                                struct xfs_bmbt_irec *, int *,
-                               struct xfs_bmap_free *);
+                               struct xfs_bmap_free *, struct xfs_extdelta *);
+typedef int            (*xfs_bunmapi_t)(struct xfs_trans *,
+                               void *, xfs_fileoff_t,
+                               xfs_filblks_t, int, xfs_extnum_t,
+                               xfs_fsblock_t *, struct xfs_bmap_free *,
+                               struct xfs_extdelta *, int *);
 typedef int            (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *);
 typedef int            (*xfs_iomap_write_direct_t)(
                                void *, xfs_off_t, size_t, int,
@@ -213,11 +220,14 @@ typedef void              (*xfs_lock_demote_t)(void *, uint);
 typedef int            (*xfs_lock_nowait_t)(void *, uint);
 typedef void           (*xfs_unlk_t)(void *, unsigned int);
 typedef xfs_fsize_t    (*xfs_size_t)(void *);
-typedef xfs_fsize_t    (*xfs_iodone_t)(struct vfs *);
+typedef xfs_fsize_t    (*xfs_iodone_t)(struct bhv_vfs *);
+typedef int            (*xfs_swap_extents_t)(void *, void *,
+                               struct xfs_swapext*);
 
 typedef struct xfs_ioops {
        xfs_ioinit_t                    xfs_ioinit;
        xfs_bmapi_t                     xfs_bmapi_func;
+       xfs_bunmapi_t                   xfs_bunmapi_func;
        xfs_bmap_eof_t                  xfs_bmap_eof_func;
        xfs_iomap_write_direct_t        xfs_iomap_write_direct;
        xfs_iomap_write_delay_t         xfs_iomap_write_delay;
@@ -230,13 +240,17 @@ typedef struct xfs_ioops {
        xfs_unlk_t                      xfs_unlock;
        xfs_size_t                      xfs_size_func;
        xfs_iodone_t                    xfs_iodone;
+       xfs_swap_extents_t              xfs_swap_extents_func;
 } xfs_ioops_t;
 
 #define XFS_IOINIT(vfsp, args, flags) \
        (*(mp)->m_io_ops.xfs_ioinit)(vfsp, args, flags)
-#define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist)    \
+#define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist,delta) \
        (*(mp)->m_io_ops.xfs_bmapi_func) \
-               (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist)
+               (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist,delta)
+#define XFS_BUNMAPI(mp, trans,io,bno,len,f,nexts,first,flist,delta,done) \
+       (*(mp)->m_io_ops.xfs_bunmapi_func) \
+               (trans,(io)->io_obj,bno,len,f,nexts,first,flist,delta,done)
 #define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \
        (*(mp)->m_io_ops.xfs_bmap_eof_func) \
                ((io)->io_obj, endoff, whichfork, eof)
@@ -266,6 +280,9 @@ typedef struct xfs_ioops {
        (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj)
 #define XFS_IODONE(vfsp) \
        (*(mp)->m_io_ops.xfs_iodone)(vfsp)
+#define XFS_SWAP_EXTENTS(mp, io, tio, sxp) \
+       (*(mp)->m_io_ops.xfs_swap_extents_func) \
+               ((io)->io_obj, (tio)->io_obj, sxp)
 
 #ifdef HAVE_PERCPU_SB
 
@@ -386,8 +403,6 @@ typedef struct xfs_mount {
        __uint8_t               m_inode_quiesce;/* call quiesce on new inodes.
                                                   field governed by m_ilock */
        __uint8_t               m_sectbb_log;   /* sectlog - BBSHIFT */
-       __uint8_t               m_dirversion;   /* 1 or 2 */
-       xfs_dirops_t            m_dirops;       /* table of dir funcs */
        int                     m_dirblksize;   /* directory block sz--bytes */
        int                     m_dirblkfsbs;   /* directory block sz--fsbs */
        xfs_dablk_t             m_dirdatablk;   /* blockno of dir data v2 */
@@ -494,16 +509,7 @@ xfs_preferred_iosize(xfs_mount_t *mp)
 
 #define XFS_FORCED_SHUTDOWN(mp)        ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
 #define xfs_force_shutdown(m,f)        \
-       VFS_FORCE_SHUTDOWN((XFS_MTOVFS(m)), f, __FILE__, __LINE__)
-
-/*
- * Flags sent to xfs_force_shutdown.
- */
-#define XFS_METADATA_IO_ERROR  0x1
-#define XFS_LOG_IO_ERROR       0x2
-#define XFS_FORCE_UMOUNT       0x4
-#define XFS_CORRUPT_INCORE     0x8     /* Corrupt in-memory data structures */
-#define XFS_SHUTDOWN_REMOTE_REQ 0x10   /* Shutdown came from remote cell */
+       bhv_vfs_force_shutdown((XFS_MTOVFS(m)), f, __FILE__, __LINE__)
 
 /*
  * Flags for xfs_mountfs
@@ -521,7 +527,7 @@ xfs_preferred_iosize(xfs_mount_t *mp)
  * Macros for getting from mount to vfs and back.
  */
 #define        XFS_MTOVFS(mp)          xfs_mtovfs(mp)
-static inline struct vfs *xfs_mtovfs(xfs_mount_t *mp)
+static inline struct bhv_vfs *xfs_mtovfs(xfs_mount_t *mp)
 {
        return bhvtovfs(&mp->m_bhv);
 }
@@ -533,7 +539,7 @@ static inline xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp)
 }
 
 #define XFS_VFSTOM(vfs) xfs_vfstom(vfs)
-static inline xfs_mount_t *xfs_vfstom(vfs_t *vfs)
+static inline xfs_mount_t *xfs_vfstom(bhv_vfs_t *vfs)
 {
        return XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfs), &xfs_vfsops));
 }
@@ -571,7 +577,7 @@ typedef struct xfs_mod_sb {
 extern xfs_mount_t *xfs_mount_init(void);
 extern void    xfs_mod_sb(xfs_trans_t *, __int64_t);
 extern void    xfs_mount_free(xfs_mount_t *mp, int remove_bhv);
-extern int     xfs_mountfs(struct vfs *, xfs_mount_t *mp, int);
+extern int     xfs_mountfs(struct bhv_vfs *, xfs_mount_t *mp, int);
 extern void    xfs_mountfs_check_barriers(xfs_mount_t *mp);
 
 extern int     xfs_unmountfs(xfs_mount_t *, struct cred *);
@@ -589,7 +595,7 @@ extern void xfs_freesb(xfs_mount_t *);
 extern void    xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
 extern int     xfs_syncsub(xfs_mount_t *, int, int, int *);
 extern int     xfs_sync_inodes(xfs_mount_t *, int, int, int *);
-extern xfs_agnumber_t  xfs_initialize_perag(struct vfs *, xfs_mount_t *,
+extern xfs_agnumber_t  xfs_initialize_perag(struct bhv_vfs *, xfs_mount_t *,
                                                xfs_agnumber_t);
 extern void    xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t);
 
index 1408a32eef886418afbb3006a5ff54cd286c161a..320d63ff9ca2ed97ca60cf0b93caad1d989faae6 100644 (file)
@@ -23,7 +23,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
index 7fbef974bce663323d24ca87c0fd9153250e78ac..acb853b33ebbd632765403361e6debf8ae90823a 100644 (file)
@@ -365,7 +365,7 @@ typedef struct xfs_dqtrxops {
 extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
 extern int xfs_mount_reset_sbqflags(struct xfs_mount *);
 
-extern struct bhv_vfsops xfs_qmops;
+extern struct bhv_module_vfsops xfs_qmops;
 
 #endif /* __KERNEL__ */
 
index 1f148762eb28e01b7854e4e7d412242a0e8c6cec..d98171deaa1ce8c983b3302c75080b78db8a10b2 100644 (file)
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -40,7 +38,6 @@
 #include "xfs_refcache.h"
 #include "xfs_utils.h"
 #include "xfs_trans_space.h"
-#include "xfs_dir_leaf.h"
 
 
 /*
@@ -87,8 +84,8 @@ STATIC int
 xfs_lock_for_rename(
        xfs_inode_t     *dp1,   /* old (source) directory inode */
        xfs_inode_t     *dp2,   /* new (target) directory inode */
-       vname_t         *vname1,/* old entry name */
-       vname_t         *vname2,/* new entry name */
+       bhv_vname_t     *vname1,/* old entry name */
+       bhv_vname_t     *vname2,/* new entry name */
        xfs_inode_t     **ipp1, /* inode of old entry */
        xfs_inode_t     **ipp2, /* inode of new entry, if it
                                   already exists, NULL otherwise. */
@@ -225,9 +222,9 @@ xfs_lock_for_rename(
 int
 xfs_rename(
        bhv_desc_t      *src_dir_bdp,
-       vname_t         *src_vname,
-       vnode_t         *target_dir_vp,
-       vname_t         *target_vname,
+       bhv_vname_t     *src_vname,
+       bhv_vnode_t     *target_dir_vp,
+       bhv_vname_t     *target_vname,
        cred_t          *credp)
 {
        xfs_trans_t     *tp;
@@ -242,7 +239,7 @@ xfs_rename(
        int             committed;
        xfs_inode_t     *inodes[4];
        int             target_ip_dropped = 0;  /* dropped target_ip link? */
-       vnode_t         *src_dir_vp;
+       bhv_vnode_t     *src_dir_vp;
        int             spaceres;
        int             target_link_zero = 0;
        int             num_inodes;
@@ -398,34 +395,29 @@ xfs_rename(
                 * fit before actually inserting it.
                 */
                if (spaceres == 0 &&
-                   (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name,
-                               target_namelen))) {
+                   (error = xfs_dir_canenter(tp, target_dp, target_name,
+                                               target_namelen)))
                        goto error_return;
-               }
                /*
                 * If target does not exist and the rename crosses
                 * directories, adjust the target directory link count
                 * to account for the ".." reference from the new entry.
                 */
-               error = XFS_DIR_CREATENAME(mp, tp, target_dp, target_name,
+               error = xfs_dir_createname(tp, target_dp, target_name,
                                           target_namelen, src_ip->i_ino,
                                           &first_block, &free_list, spaceres);
-               if (error == ENOSPC) {
+               if (error == ENOSPC)
                        goto error_return;
-               }
-               if (error) {
+               if (error)
                        goto abort_return;
-               }
                xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
                if (new_parent && src_is_directory) {
                        error = xfs_bumplink(tp, target_dp);
-                       if (error) {
+                       if (error)
                                goto abort_return;
-                       }
                }
        } else { /* target_ip != NULL */
-
                /*
                 * If target exists and it's a directory, check that both
                 * target and source are directories and that target can be
@@ -435,7 +427,7 @@ xfs_rename(
                        /*
                         * Make sure target dir is empty.
                         */
-                       if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) ||
+                       if (!(xfs_dir_isempty(target_ip)) ||
                            (target_ip->i_d.di_nlink > 2)) {
                                error = XFS_ERROR(EEXIST);
                                goto error_return;
@@ -451,12 +443,11 @@ xfs_rename(
                 * In case there is already an entry with the same
                 * name at the destination directory, remove it first.
                 */
-               error = XFS_DIR_REPLACE(mp, tp, target_dp, target_name,
-                       target_namelen, src_ip->i_ino, &first_block,
-                       &free_list, spaceres);
-               if (error) {
+               error = xfs_dir_replace(tp, target_dp, target_name,
+                                       target_namelen, src_ip->i_ino,
+                                       &first_block, &free_list, spaceres);
+               if (error)
                        goto abort_return;
-               }
                xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
                /*
@@ -464,9 +455,8 @@ xfs_rename(
                 * dir no longer points to it.
                 */
                error = xfs_droplink(tp, target_ip);
-               if (error) {
+               if (error)
                        goto abort_return;
-               }
                target_ip_dropped = 1;
 
                if (src_is_directory) {
@@ -474,9 +464,8 @@ xfs_rename(
                         * Drop the link from the old "." entry.
                         */
                        error = xfs_droplink(tp, target_ip);
-                       if (error) {
+                       if (error)
                                goto abort_return;
-                       }
                }
 
                /* Do this test while we still hold the locks */
@@ -488,18 +477,15 @@ xfs_rename(
         * Remove the source.
         */
        if (new_parent && src_is_directory) {
-
                /*
                 * Rewrite the ".." entry to point to the new
                 * directory.
                 */
-               error = XFS_DIR_REPLACE(mp, tp, src_ip, "..", 2,
-                                       target_dp->i_ino, &first_block,
-                                       &free_list, spaceres);
+               error = xfs_dir_replace(tp, src_ip, "..", 2, target_dp->i_ino,
+                                       &first_block, &free_list, spaceres);
                ASSERT(error != EEXIST);
-               if (error) {
+               if (error)
                        goto abort_return;
-               }
                xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
        } else {
@@ -527,16 +513,14 @@ xfs_rename(
                 * entry that's moved no longer points to it.
                 */
                error = xfs_droplink(tp, src_dp);
-               if (error) {
+               if (error)
                        goto abort_return;
-               }
        }
 
-       error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen,
+       error = xfs_dir_removename(tp, src_dp, src_name, src_namelen,
                        src_ip->i_ino, &first_block, &free_list, spaceres);
-       if (error) {
+       if (error)
                goto abort_return;
-       }
        xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
        /*
@@ -609,7 +593,7 @@ xfs_rename(
         * Let interposed file systems know about removed links.
         */
        if (target_ip_dropped) {
-               VOP_LINK_REMOVED(XFS_ITOV(target_ip), target_dir_vp,
+               bhv_vop_link_removed(XFS_ITOV(target_ip), target_dir_vp,
                                        target_link_zero);
                IRELE(target_ip);
        }
index 5b413946b1c5dad1e93c4cbbfed467f10938795d..0c1e42b037efe63058819f275e20b0fd7cf9186b 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -141,7 +139,7 @@ xfs_growfs_rt_alloc(
                cancelflags |= XFS_TRANS_ABORT;
                error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks,
                        XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock,
-                       resblks, &map, &nmap, &flist);
+                       resblks, &map, &nmap, &flist, NULL);
                if (!error && nmap < 1)
                        error = XFS_ERROR(ENOSPC);
                if (error)
@@ -2404,10 +2402,10 @@ xfs_rtprint_range(
 {
        xfs_extlen_t    i;              /* block number in the extent */
 
-       printk("%Ld: ", (long long)start);
+       cmn_err(CE_DEBUG, "%Ld: ", (long long)start);
        for (i = 0; i < len; i++)
-               printk("%d", xfs_rtcheck_bit(mp, tp, start + i, 1));
-       printk("\n");
+               cmn_err(CE_DEBUG, "%d", xfs_rtcheck_bit(mp, tp, start + i, 1));
+       cmn_err(CE_DEBUG, "\n");
 }
 
 /*
@@ -2431,17 +2429,17 @@ xfs_rtprint_summary(
                        (void)xfs_rtget_summary(mp, tp, l, i, &sumbp, &sb, &c);
                        if (c) {
                                if (!p) {
-                                       printk("%Ld-%Ld:", 1LL << l,
+                                       cmn_err(CE_DEBUG, "%Ld-%Ld:", 1LL << l,
                                                XFS_RTMIN((1LL << l) +
                                                          ((1LL << l) - 1LL),
                                                         mp->m_sb.sb_rextents));
                                        p = 1;
                                }
-                               printk(" %Ld:%d", (long long)i, c);
+                               cmn_err(CE_DEBUG, " %Ld:%d", (long long)i, c);
                        }
                }
                if (p)
-                       printk("\n");
+                       cmn_err(CE_DEBUG, "\n");
        }
        if (sumbp)
                xfs_trans_brelse(tp, sumbp);
index a59c102cf214b08e1bd47493439159ad59dd4b6b..defb2febaaf5c68d5cb3663cbb764150fecff0e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -91,6 +89,90 @@ xfs_write_clear_setuid(
        return 0;
 }
 
+/*
+ * Handle logging requirements of various synchronous types of write.
+ */
+int
+xfs_write_sync_logforce(
+       xfs_mount_t     *mp,
+       xfs_inode_t     *ip)
+{
+       int             error = 0;
+
+       /*
+        * If we're treating this as O_DSYNC and we have not updated the
+        * size, force the log.
+        */
+       if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) &&
+           !(ip->i_update_size)) {
+               xfs_inode_log_item_t    *iip = ip->i_itemp;
+
+               /*
+                * If an allocation transaction occurred
+                * without extending the size, then we have to force
+                * the log up the proper point to ensure that the
+                * allocation is permanent.  We can't count on
+                * the fact that buffered writes lock out direct I/O
+                * writes - the direct I/O write could have extended
+                * the size nontransactionally, then finished before
+                * we started.  xfs_write_file will think that the file
+                * didn't grow but the update isn't safe unless the
+                * size change is logged.
+                *
+                * Force the log if we've committed a transaction
+                * against the inode or if someone else has and
+                * the commit record hasn't gone to disk (e.g.
+                * the inode is pinned).  This guarantees that
+                * all changes affecting the inode are permanent
+                * when we return.
+                */
+               if (iip && iip->ili_last_lsn) {
+                       xfs_log_force(mp, iip->ili_last_lsn,
+                                       XFS_LOG_FORCE | XFS_LOG_SYNC);
+               } else if (xfs_ipincount(ip) > 0) {
+                       xfs_log_force(mp, (xfs_lsn_t)0,
+                                       XFS_LOG_FORCE | XFS_LOG_SYNC);
+               }
+
+       } else {
+               xfs_trans_t     *tp;
+
+               /*
+                * O_SYNC or O_DSYNC _with_ a size update are handled
+                * the same way.
+                *
+                * If the write was synchronous then we need to make
+                * sure that the inode modification time is permanent.
+                * We'll have updated the timestamp above, so here
+                * we use a synchronous transaction to log the inode.
+                * It's not fast, but it's necessary.
+                *
+                * If this a dsync write and the size got changed
+                * non-transactionally, then we need to ensure that
+                * the size change gets logged in a synchronous
+                * transaction.
+                */
+               tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC);
+               if ((error = xfs_trans_reserve(tp, 0,
+                                               XFS_SWRITE_LOG_RES(mp),
+                                               0, 0, 0))) {
+                       /* Transaction reserve failed */
+                       xfs_trans_cancel(tp, 0);
+               } else {
+                       /* Transaction reserve successful */
+                       xfs_ilock(ip, XFS_ILOCK_EXCL);
+                       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+                       xfs_trans_ihold(tp, ip);
+                       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+                       xfs_trans_set_sync(tp);
+                       error = xfs_trans_commit(tp, 0, NULL);
+                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               }
+       }
+
+       return error;
+}
+
 /*
  * Force a shutdown of the filesystem instantly while keeping
  * the filesystem consistent. We don't do an unmount here; just shutdown
@@ -109,12 +191,12 @@ xfs_do_force_shutdown(
        xfs_mount_t     *mp;
 
        mp = XFS_BHVTOM(bdp);
-       logerror = flags & XFS_LOG_IO_ERROR;
+       logerror = flags & SHUTDOWN_LOG_IO_ERROR;
 
-       if (!(flags & XFS_FORCE_UMOUNT)) {
-               cmn_err(CE_NOTE,
-               "xfs_force_shutdown(%s,0x%x) called from line %d of file %s.  Return address = 0x%p",
-                       mp->m_fsname,flags,lnnum,fname,__return_address);
+       if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
+               cmn_err(CE_NOTE, "xfs_force_shutdown(%s,0x%x) called from "
+                                "line %d of file %s.  Return address = 0x%p",
+                       mp->m_fsname, flags, lnnum, fname, __return_address);
        }
        /*
         * No need to duplicate efforts.
@@ -125,33 +207,37 @@ xfs_do_force_shutdown(
        /*
         * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
         * queue up anybody new on the log reservations, and wakes up
-        * everybody who's sleeping on log reservations and tells
-        * them the bad news.
+        * everybody who's sleeping on log reservations to tell them
+        * the bad news.
         */
        if (xfs_log_force_umount(mp, logerror))
                return;
 
-       if (flags & XFS_CORRUPT_INCORE) {
+       if (flags & SHUTDOWN_CORRUPT_INCORE) {
                xfs_cmn_err(XFS_PTAG_SHUTDOWN_CORRUPT, CE_ALERT, mp,
     "Corruption of in-memory data detected.  Shutting down filesystem: %s",
                        mp->m_fsname);
                if (XFS_ERRLEVEL_HIGH <= xfs_error_level) {
                        xfs_stack_trace();
                }
-       } else if (!(flags & XFS_FORCE_UMOUNT)) {
+       } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
                if (logerror) {
                        xfs_cmn_err(XFS_PTAG_SHUTDOWN_LOGERROR, CE_ALERT, mp,
-                       "Log I/O Error Detected.  Shutting down filesystem: %s",
+               "Log I/O Error Detected.  Shutting down filesystem: %s",
+                               mp->m_fsname);
+               } else if (flags & SHUTDOWN_DEVICE_REQ) {
+                       xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp,
+               "All device paths lost.  Shutting down filesystem: %s",
                                mp->m_fsname);
-               } else if (!(flags & XFS_SHUTDOWN_REMOTE_REQ)) {
+               } else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
                        xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp,
-                               "I/O Error Detected.  Shutting down filesystem: %s",
+               "I/O Error Detected.  Shutting down filesystem: %s",
                                mp->m_fsname);
                }
        }
-       if (!(flags & XFS_FORCE_UMOUNT)) {
-               cmn_err(CE_ALERT,
-               "Please umount the filesystem, and rectify the problem(s)");
+       if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
+               cmn_err(CE_ALERT, "Please umount the filesystem, "
+                                 "and rectify the problem(s)");
        }
 }
 
@@ -335,7 +421,7 @@ xfs_bwrite(
                 * from bwrite and we could be tracing a buffer that has
                 * been reused.
                 */
-               xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
        }
        return (error);
 }
index e63795644478766d6a5956da20891b4b732ba70f..188b296ff50c663cdaeda26b2a9f7341bb953130 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -75,6 +75,7 @@ xfs_fsb_to_db_io(struct xfs_iocore *io, xfs_fsblock_t fsb)
  * Prototypes for functions in xfs_rw.c.
  */
 extern int xfs_write_clear_setuid(struct xfs_inode *ip);
+extern int xfs_write_sync_logforce(struct xfs_mount *mp, struct xfs_inode *ip);
 extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp);
 extern int xfs_bioerror(struct xfs_buf *bp);
 extern int xfs_bioerror_relse(struct xfs_buf *bp);
@@ -87,9 +88,10 @@ extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp,
 /*
  * Prototypes for functions in xfs_vnodeops.c.
  */
-extern int xfs_rwlock(bhv_desc_t *bdp, vrwlock_t write_lock);
-extern void xfs_rwunlock(bhv_desc_t *bdp, vrwlock_t write_lock);
-extern int xfs_setattr(bhv_desc_t *bdp, vattr_t *vap, int flags, cred_t *credp);
+extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
+extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
+extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags,
+                      cred_t *credp);
 extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf,
                                 xfs_off_t offset, cred_t *credp, int flags);
 extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state,
index 8d056cef5d1ffd27844aaa91702136406ac1f0d3..ee2721e0de4d7fd700e22e8a3b635255c14696cc 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -33,7 +32,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -236,11 +234,8 @@ xfs_trans_alloc(
        xfs_mount_t     *mp,
        uint            type)
 {
-       fs_check_frozen(XFS_MTOVFS(mp), SB_FREEZE_TRANS);
-       atomic_inc(&mp->m_active_trans);
-
-       return (_xfs_trans_alloc(mp, type));
-
+       vfs_wait_for_freeze(XFS_MTOVFS(mp), SB_FREEZE_TRANS);
+       return _xfs_trans_alloc(mp, type);
 }
 
 xfs_trans_t *
@@ -250,12 +245,9 @@ _xfs_trans_alloc(
 {
        xfs_trans_t     *tp;
 
-       ASSERT(xfs_trans_zone != NULL);
-       tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
+       atomic_inc(&mp->m_active_trans);
 
-       /*
-        * Initialize the transaction structure.
-        */
+       tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP);
        tp->t_magic = XFS_TRANS_MAGIC;
        tp->t_type = type;
        tp->t_mountp = mp;
@@ -263,8 +255,7 @@ _xfs_trans_alloc(
        tp->t_busy_free = XFS_LBC_NUM_SLOTS;
        XFS_LIC_INIT(&(tp->t_items));
        XFS_LBC_INIT(&(tp->t_busy));
-
-       return (tp);
+       return tp;
 }
 
 /*
@@ -303,7 +294,7 @@ xfs_trans_dup(
        tp->t_blk_res = tp->t_blk_res_used;
        ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
        tp->t_rtx_res = tp->t_rtx_res_used;
-       PFLAGS_DUP(&tp->t_pflags, &ntp->t_pflags);
+       ntp->t_pflags = tp->t_pflags;
 
        XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp);
 
@@ -335,14 +326,11 @@ xfs_trans_reserve(
        uint            logcount)
 {
        int             log_flags;
-       int             error;
-       int     rsvd;
-
-       error = 0;
-       rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
+       int             error = 0;
+       int             rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
 
        /* Mark this thread as being in a transaction */
-        PFLAGS_SET_FSTRANS(&tp->t_pflags);
+       current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
 
        /*
         * Attempt to reserve the needed disk blocks by decrementing
@@ -353,7 +341,7 @@ xfs_trans_reserve(
                error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
                                          -blocks, rsvd);
                if (error != 0) {
-                        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
+                       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
                        return (XFS_ERROR(ENOSPC));
                }
                tp->t_blk_res += blocks;
@@ -426,9 +414,9 @@ undo_blocks:
                tp->t_blk_res = 0;
        }
 
-        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
+       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
 
-       return (error);
+       return error;
 }
 
 
@@ -819,7 +807,7 @@ shut_us_down:
                        if (commit_lsn == -1 && !shutdown)
                                shutdown = XFS_ERROR(EIO);
                }
-                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
+               current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
                xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
                xfs_trans_free_busy(tp);
                xfs_trans_free(tp);
@@ -846,7 +834,7 @@ shut_us_down:
         */
        nvec = xfs_trans_count_vecs(tp);
        if (nvec == 0) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
                goto shut_us_down;
        } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
                log_vector = log_vector_fast;
@@ -884,7 +872,7 @@ shut_us_down:
         * had pinned, clean up, free trans structure, and return error.
         */
        if (error || commit_lsn == -1) {
-                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
+               current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
                xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
                return XFS_ERROR(EIO);
        }
@@ -926,7 +914,7 @@ shut_us_down:
        /*
         * Mark this thread as no longer being in a transaction
         */
-       PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
+       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
 
        /*
         * Once all the items of the transaction have been copied
@@ -1148,7 +1136,7 @@ xfs_trans_cancel(
         */
        if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) {
                XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp);
-               xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+               xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
        }
 #ifdef DEBUG
        if (!(flags & XFS_TRANS_ABORT)) {
@@ -1182,7 +1170,7 @@ xfs_trans_cancel(
        }
 
        /* mark this thread as no longer being in a transaction */
-        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
+       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
 
        xfs_trans_free_items(tp, flags);
        xfs_trans_free_busy(tp);
index 100d9a4b38ee9ad9e0842fd62b8187d0ed51a794..cb65c3a603f56a776cfef5a7a0def8c6f2d77108 100644 (file)
@@ -805,12 +805,9 @@ typedef struct xfs_trans {
        ((mp)->m_sb.sb_inodesize + \
         (mp)->m_sb.sb_sectsize * 2 + \
         (mp)->m_dirblksize + \
-        (XFS_DIR_IS_V1(mp) ? 0 : \
-           XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1))) + \
+        XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1)) + \
         XFS_ALLOCFREE_LOG_RES(mp, 1) + \
-        (128 * (4 + \
-                (XFS_DIR_IS_V1(mp) ? 0 : \
-                        XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \
+        (128 * (4 + (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \
                 XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
 
 #define        XFS_ADDAFORK_LOG_RES(mp)        ((mp)->m_reservations.tr_addafork)
index 19ab24af1c1c09878459012c9c90479e5d2f6977..558c87ff0c41faeea2da96536da6cf250c2e095d 100644 (file)
@@ -22,7 +22,6 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
@@ -363,9 +362,10 @@ xfs_trans_delete_ail(
                        AIL_UNLOCK(mp, s);
                else {
                        xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp,
-                               "xfs_trans_delete_ail: attempting to delete a log item that is not in the AIL");
+               "%s: attempting to delete a log item that is not in the AIL",
+                                       __FUNCTION__);
                        AIL_UNLOCK(mp, s);
-                       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
                }
        }
 }
index c74c31ebc81c535658e0417210ddaf3556d4d5f1..60b6b898022bcb1be98f96f2a21615e1bff5e131 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -320,7 +318,7 @@ xfs_trans_read_buf(
                        if (xfs_error_target == target) {
                                if (((xfs_req_num++) % xfs_error_mod) == 0) {
                                        xfs_buf_relse(bp);
-                                       printk("Returning error!\n");
+                                       cmn_err(CE_DEBUG, "Returning error!\n");
                                        return XFS_ERROR(EIO);
                                }
                        }
@@ -369,7 +367,7 @@ xfs_trans_read_buf(
                                 */
                                if (tp->t_flags & XFS_TRANS_DIRTY)
                                        xfs_force_shutdown(tp->t_mountp,
-                                                          XFS_METADATA_IO_ERROR);
+                                                       SHUTDOWN_META_IO_ERROR);
                                return error;
                        }
                }
@@ -414,7 +412,7 @@ xfs_trans_read_buf(
                xfs_ioerror_alert("xfs_trans_read_buf", mp,
                                  bp, blkno);
                if (tp->t_flags & XFS_TRANS_DIRTY)
-                       xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR);
+                       xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR);
                xfs_buf_relse(bp);
                return error;
        }
@@ -423,9 +421,9 @@ xfs_trans_read_buf(
                if (xfs_error_target == target) {
                        if (((xfs_req_num++) % xfs_error_mod) == 0) {
                                xfs_force_shutdown(tp->t_mountp,
-                                                  XFS_METADATA_IO_ERROR);
+                                                  SHUTDOWN_META_IO_ERROR);
                                xfs_buf_relse(bp);
-                               printk("Returning error in trans!\n");
+                               cmn_err(CE_DEBUG, "Returning trans error!\n");
                                return XFS_ERROR(EIO);
                        }
                }
index 7d7d627f25df834be81689802c1f53b836ec3a45..b290270dd4a69f941d18d98a16bf840ed57d25c4 100644 (file)
@@ -22,7 +22,6 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
-#include "xfs_dir.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
index 7c5894d59f810c08686f4666bfd4a3c546a76974..b8db1d5cde5a1fac03837ae85f130c7091775925 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
index 1117d600d74108f2ba9936663db4c5f758062a85..2912aac07c7bff8d7133a54297c78d6707a6669c 100644 (file)
@@ -493,7 +493,7 @@ xfs_trans_add_busy(xfs_trans_t *tp, xfs_agnumber_t ag, xfs_extlen_t idx)
                                break;
                        } else {
                                /* out-of-order vacancy */
-                               printk("OOO vacancy lbcp 0x%p\n", lbcp);
+                               cmn_err(CE_DEBUG, "OOO vacancy lbcp 0x%p\n", lbcp);
                                ASSERT(0);
                        }
                }
index 7fe3792b18df6cfc633c1b22068012c5b58074aa..4ea2e5074bdd2e68a7ea943191ddd60effdac791 100644 (file)
@@ -30,8 +30,7 @@
          XFS_EXTENTADD_SPACE_RES(mp,w))
 #define        XFS_DAENTER_1B(mp,w)    ((w) == XFS_DATA_FORK ? (mp)->m_dirblkfsbs : 1)
 #define        XFS_DAENTER_DBS(mp,w)   \
-       (XFS_DA_NODE_MAXDEPTH + \
-        ((XFS_DIR_IS_V2(mp) && (w) == XFS_DATA_FORK) ? 2 : 0))
+       (XFS_DA_NODE_MAXDEPTH + (((w) == XFS_DATA_FORK) ? 2 : 0))
 #define        XFS_DAENTER_BLOCKS(mp,w)        \
        (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w))
 #define        XFS_DAENTER_BMAP1B(mp,w)        \
 #define        XFS_DAENTER_SPACE_RES(mp,w)     \
        (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w))
 #define        XFS_DAREMOVE_SPACE_RES(mp,w)    XFS_DAENTER_BMAPS(mp,w)
-#define        XFS_DIRENTER_MAX_SPLIT(mp,nl)   \
-       (((mp)->m_sb.sb_blocksize == 512 && \
-         XFS_DIR_IS_V1(mp) && \
-         (nl) >= XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN) ? 2 : 1)
+#define        XFS_DIRENTER_MAX_SPLIT(mp,nl)   1
 #define        XFS_DIRENTER_SPACE_RES(mp,nl)   \
        (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \
         XFS_DIRENTER_MAX_SPLIT(mp,nl))
@@ -57,8 +53,7 @@
  * Space reservation values for various transactions.
  */
 #define        XFS_ADDAFORK_SPACE_RES(mp)      \
-       ((mp)->m_dirblkfsbs + \
-        (XFS_DIR_IS_V1(mp) ? 0 : XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK)))
+       ((mp)->m_dirblkfsbs + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK))
 #define        XFS_ATTRRM_SPACE_RES(mp)        \
        XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK)
 /* This macro is not used - see inline code in xfs_attr_set */
index 34654ec6ae106e45a2d508556cb09e70b18a40dd..9014d7e444885faa447c2a7a987c1f4bdcd1bf8e 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
  */
 int
 xfs_get_dir_entry(
-       vname_t         *dentry,
+       bhv_vname_t     *dentry,
        xfs_inode_t     **ipp)
 {
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        vp = VNAME_TO_VNODE(dentry);
 
@@ -69,11 +67,11 @@ int
 xfs_dir_lookup_int(
        bhv_desc_t      *dir_bdp,
        uint            lock_mode,
-       vname_t         *dentry,
+       bhv_vname_t     *dentry,
        xfs_ino_t       *inum,
        xfs_inode_t     **ipp)
 {
-       vnode_t         *dir_vp;
+       bhv_vnode_t     *dir_vp;
        xfs_inode_t     *dp;
        int             error;
 
@@ -82,8 +80,7 @@ xfs_dir_lookup_int(
 
        dp = XFS_BHVTOI(dir_bdp);
 
-       error = XFS_DIR_LOOKUP(dp->i_mount, NULL, dp,
-                               VNAME(dentry), VNAMELEN(dentry), inum);
+       error = xfs_dir_lookup(NULL, dp, VNAME(dentry), VNAMELEN(dentry), inum);
        if (!error) {
                /*
                 * Unlock the directory. We do this because we can't
index 472661a3b6d86e85f668d11cbfc944284d5da46a..fe953e98afa7a332cfaa4e7e8beb180c94ba4368 100644 (file)
 #define        ITRACE(ip)      vn_trace_ref(XFS_ITOV(ip), __FILE__, __LINE__, \
                                (inst_t *)__return_address)
 
-extern int xfs_rename (bhv_desc_t *, vname_t *, vnode_t *, vname_t *, cred_t *);
-extern int xfs_get_dir_entry (vname_t *, xfs_inode_t **);
-extern int xfs_dir_lookup_int (bhv_desc_t *, uint, vname_t *, xfs_ino_t *,
+extern int xfs_rename (bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *,
+                       bhv_vname_t *, cred_t *);
+extern int xfs_get_dir_entry (bhv_vname_t *, xfs_inode_t **);
+extern int xfs_dir_lookup_int (bhv_desc_t *, uint, bhv_vname_t *, xfs_ino_t *,
                                xfs_inode_t **);
 extern int xfs_truncate_file (xfs_mount_t *, xfs_inode_t *);
 extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t,
index 36ea1b2094f29cf6c2a475fce994e8e15a4e0008..6c96391f3f1aad091982840e85e13d107757f461 100644 (file)
@@ -24,7 +24,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -32,7 +31,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_alloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -131,9 +129,6 @@ xfs_init(void)
 #ifdef XFS_BMBT_TRACE
        xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_SLEEP);
 #endif
-#ifdef XFS_DIR_TRACE
-       xfs_dir_trace_buf = ktrace_alloc(XFS_DIR_TRACE_SIZE, KM_SLEEP);
-#endif
 #ifdef XFS_ATTR_TRACE
        xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_SLEEP);
 #endif
@@ -177,9 +172,6 @@ xfs_cleanup(void)
 #ifdef XFS_ATTR_TRACE
        ktrace_free(xfs_attr_trace_buf);
 #endif
-#ifdef XFS_DIR_TRACE
-       ktrace_free(xfs_dir_trace_buf);
-#endif
 #ifdef XFS_BMBT_TRACE
        ktrace_free(xfs_bmbt_trace_buf);
 #endif
@@ -212,7 +204,7 @@ xfs_cleanup(void)
  */
 STATIC int
 xfs_start_flags(
-       struct vfs              *vfs,
+       struct bhv_vfs          *vfs,
        struct xfs_mount_args   *ap,
        struct xfs_mount        *mp)
 {
@@ -337,7 +329,7 @@ xfs_start_flags(
  */
 STATIC int
 xfs_finish_flags(
-       struct vfs              *vfs,
+       struct bhv_vfs          *vfs,
        struct xfs_mount_args   *ap,
        struct xfs_mount        *mp)
 {
@@ -423,7 +415,7 @@ xfs_mount(
        struct xfs_mount_args   *args,
        cred_t                  *credp)
 {
-       struct vfs              *vfsp = bhvtovfs(bhvp);
+       struct bhv_vfs          *vfsp = bhvtovfs(bhvp);
        struct bhv_desc         *p;
        struct xfs_mount        *mp = XFS_BHVTOM(bhvp);
        struct block_device     *ddev, *logdev, *rtdev;
@@ -552,10 +544,10 @@ xfs_unmount(
        int             flags,
        cred_t          *credp)
 {
-       struct vfs      *vfsp = bhvtovfs(bdp);
+       bhv_vfs_t       *vfsp = bhvtovfs(bdp);
        xfs_mount_t     *mp = XFS_BHVTOM(bdp);
        xfs_inode_t     *rip;
-       vnode_t         *rvp;
+       bhv_vnode_t     *rvp;
        int             unmount_event_wanted = 0;
        int             unmount_event_flags = 0;
        int             xfs_unmountfs_needed = 0;
@@ -665,9 +657,8 @@ xfs_mntupdate(
        int                             *flags,
        struct xfs_mount_args           *args)
 {
-       struct vfs      *vfsp = bhvtovfs(bdp);
+       bhv_vfs_t       *vfsp = bhvtovfs(bdp);
        xfs_mount_t     *mp = XFS_BHVTOM(bdp);
-       int             error;
 
        if (!(*flags & MS_RDONLY)) {                    /* rw/ro -> rw */
                if (vfsp->vfs_flag & VFS_RDONLY)
@@ -679,7 +670,7 @@ xfs_mntupdate(
                        mp->m_flags &= ~XFS_MOUNT_BARRIER;
                }
        } else if (!(vfsp->vfs_flag & VFS_RDONLY)) {    /* rw -> ro */
-               VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL, error);
+               bhv_vfs_sync(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL);
                xfs_quiesce_fs(mp);
                xfs_log_unmount_write(mp);
                xfs_unmountfs_writesb(mp);
@@ -702,7 +693,7 @@ xfs_unmount_flush(
        xfs_inode_t     *rip = mp->m_rootip;
        xfs_inode_t     *rbmip;
        xfs_inode_t     *rsumip = NULL;
-       vnode_t         *rvp = XFS_ITOV(rip);
+       bhv_vnode_t     *rvp = XFS_ITOV(rip);
        int             error;
 
        xfs_ilock(rip, XFS_ILOCK_EXCL);
@@ -781,9 +772,9 @@ fscorrupt_out2:
 STATIC int
 xfs_root(
        bhv_desc_t      *bdp,
-       vnode_t         **vpp)
+       bhv_vnode_t     **vpp)
 {
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip);
        VN_HOLD(vp);
@@ -801,8 +792,8 @@ xfs_root(
 STATIC int
 xfs_statvfs(
        bhv_desc_t      *bdp,
-       xfs_statfs_t    *statp,
-       vnode_t         *vp)
+       bhv_statvfs_t   *statp,
+       bhv_vnode_t     *vp)
 {
        __uint64_t      fakeinos;
        xfs_extlen_t    lsize;
@@ -900,7 +891,7 @@ xfs_sync(
 /*
  * xfs sync routine for internal use
  *
- * This routine supports all of the flags defined for the generic VFS_SYNC
+ * This routine supports all of the flags defined for the generic vfs_sync
  * interface as explained above under xfs_sync.  In the interests of not
  * changing interfaces within the 6.5 family, additional internally-
  * required functions are specified within a separate xflags parameter,
@@ -917,7 +908,7 @@ xfs_sync_inodes(
        xfs_inode_t     *ip = NULL;
        xfs_inode_t     *ip_next;
        xfs_buf_t       *bp;
-       vnode_t         *vp = NULL;
+       bhv_vnode_t     *vp = NULL;
        int             error;
        int             last_error;
        uint64_t        fflag;
@@ -1156,9 +1147,9 @@ xfs_sync_inodes(
                        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
                        if (XFS_FORCED_SHUTDOWN(mp)) {
-                               VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF);
+                               bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
                        } else {
-                               VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF);
+                               bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
                        }
 
                        xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -1178,8 +1169,8 @@ xfs_sync_inodes(
                                 * across calls to the buffer cache.
                                 */
                                xfs_iunlock(ip, XFS_ILOCK_SHARED);
-                               VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1,
-                                                       fflag, FI_NONE, error);
+                               error = bhv_vop_flush_pages(vp, (xfs_off_t)0,
+                                                       -1, fflag, FI_NONE);
                                xfs_ilock(ip, XFS_ILOCK_SHARED);
                        }
 
@@ -1231,9 +1222,7 @@ xfs_sync_inodes(
                                                 * marker and free it.
                                                 */
                                                XFS_MOUNT_ILOCK(mp);
-
                                                IPOINTER_REMOVE(ip, mp);
-
                                                XFS_MOUNT_IUNLOCK(mp);
 
                                                ASSERT(!(lock_flags &
@@ -1421,7 +1410,7 @@ xfs_sync_inodes(
 /*
  * xfs sync routine for internal use
  *
- * This routine supports all of the flags defined for the generic VFS_SYNC
+ * This routine supports all of the flags defined for the generic vfs_sync
  * interface as explained above under xfs_sync.  In the interests of not
  * changing interfaces within the 6.5 family, additional internally-
  * required functions are specified within a separate xflags parameter,
@@ -1574,7 +1563,7 @@ xfs_syncsub(
 STATIC int
 xfs_vget(
        bhv_desc_t      *bdp,
-       vnode_t         **vpp,
+       bhv_vnode_t     **vpp,
        fid_t           *fidp)
 {
        xfs_mount_t     *mp = XFS_BHVTOM(bdp);
@@ -1657,10 +1646,10 @@ xfs_vget(
 #define MNTOPT_NOATTR2 "noattr2"       /* do not use attr2 attribute format */
 
 STATIC unsigned long
-suffix_strtoul(const char *cp, char **endp, unsigned int base)
+suffix_strtoul(char *s, char **endp, unsigned int base)
 {
        int     last, shift_left_factor = 0;
-       char    *value = (char *)cp;
+       char    *value = s;
 
        last = strlen(value) - 1;
        if (value[last] == 'K' || value[last] == 'k') {
@@ -1676,7 +1665,7 @@ suffix_strtoul(const char *cp, char **endp, unsigned int base)
                value[last] = '\0';
        }
 
-       return simple_strtoul(cp, endp, base) << shift_left_factor;
+       return simple_strtoul((const char *)s, endp, base) << shift_left_factor;
 }
 
 STATIC int
@@ -1686,7 +1675,7 @@ xfs_parseargs(
        struct xfs_mount_args   *args,
        int                     update)
 {
-       struct vfs              *vfsp = bhvtovfs(bhv);
+       bhv_vfs_t               *vfsp = bhvtovfs(bhv);
        char                    *this_char, *value, *eov;
        int                     dsunit, dswidth, vol_dsunit, vol_dswidth;
        int                     iosize;
@@ -1708,42 +1697,48 @@ xfs_parseargs(
 
                if (!strcmp(this_char, MNTOPT_LOGBUFS)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        args->logbufs = simple_strtoul(value, &eov, 10);
                } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        args->logbufsize = suffix_strtoul(value, &eov, 10);
                } else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        strncpy(args->logname, value, MAXNAMELEN);
                } else if (!strcmp(this_char, MNTOPT_MTPT)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        strncpy(args->mtpt, value, MAXNAMELEN);
                } else if (!strcmp(this_char, MNTOPT_RTDEV)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        strncpy(args->rtname, value, MAXNAMELEN);
                } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -1752,7 +1747,8 @@ xfs_parseargs(
                        args->iosizelog = (uint8_t) iosize;
                } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -1761,7 +1757,8 @@ xfs_parseargs(
                        args->iosizelog = ffs(iosize) - 1;
                } else if (!strcmp(this_char, MNTOPT_IHASHSIZE)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -1782,7 +1779,8 @@ xfs_parseargs(
                } else if (!strcmp(this_char, MNTOPT_INO64)) {
                        args->flags |= XFSMNT_INO64;
 #if !XFS_BIG_INUMS
-                       printk("XFS: %s option not allowed on this system\n",
+                       cmn_err(CE_WARN,
+                               "XFS: %s option not allowed on this system",
                                this_char);
                        return EINVAL;
 #endif
@@ -1792,14 +1790,16 @@ xfs_parseargs(
                        args->flags |= XFSMNT_SWALLOC;
                } else if (!strcmp(this_char, MNTOPT_SUNIT)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        dsunit = simple_strtoul(value, &eov, 10);
                } else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
                        if (!value || !*value) {
-                               printk("XFS: %s option requires an argument\n",
+                               cmn_err(CE_WARN,
+                                       "XFS: %s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -1807,7 +1807,8 @@ xfs_parseargs(
                } else if (!strcmp(this_char, MNTOPT_64BITINODE)) {
                        args->flags &= ~XFSMNT_32BITINODES;
 #if !XFS_BIG_INUMS
-                       printk("XFS: %s option not allowed on this system\n",
+                       cmn_err(CE_WARN,
+                               "XFS: %s option not allowed on this system",
                                this_char);
                        return EINVAL;
 #endif
@@ -1831,36 +1832,41 @@ xfs_parseargs(
                        args->flags &= ~XFSMNT_ATTR2;
                } else if (!strcmp(this_char, "osyncisdsync")) {
                        /* no-op, this is now the default */
-printk("XFS: osyncisdsync is now the default, option is deprecated.\n");
+                       cmn_err(CE_WARN,
+       "XFS: osyncisdsync is now the default, option is deprecated.");
                } else if (!strcmp(this_char, "irixsgid")) {
-printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n");
+                       cmn_err(CE_WARN,
+       "XFS: irixsgid is now a sysctl(2) variable, option is deprecated.");
                } else {
-                       printk("XFS: unknown mount option [%s].\n", this_char);
+                       cmn_err(CE_WARN,
+                               "XFS: unknown mount option [%s].", this_char);
                        return EINVAL;
                }
        }
 
        if (args->flags & XFSMNT_NORECOVERY) {
                if ((vfsp->vfs_flag & VFS_RDONLY) == 0) {
-                       printk("XFS: no-recovery mounts must be read-only.\n");
+                       cmn_err(CE_WARN,
+                               "XFS: no-recovery mounts must be read-only.");
                        return EINVAL;
                }
        }
 
        if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) {
-               printk(
-       "XFS: sunit and swidth options incompatible with the noalign option\n");
+               cmn_err(CE_WARN,
+       "XFS: sunit and swidth options incompatible with the noalign option");
                return EINVAL;
        }
 
        if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
-               printk("XFS: sunit and swidth must be specified together\n");
+               cmn_err(CE_WARN,
+                       "XFS: sunit and swidth must be specified together");
                return EINVAL;
        }
 
        if (dsunit && (dswidth % dsunit != 0)) {
-               printk(
-       "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)\n",
+               cmn_err(CE_WARN,
+       "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)",
                        dswidth, dsunit);
                return EINVAL;
        }
@@ -1907,7 +1913,7 @@ xfs_showargs(
        };
        struct proc_xfs_info    *xfs_infop;
        struct xfs_mount        *mp = XFS_BHVTOM(bhv);
-       struct vfs              *vfsp = XFS_MTOVFS(mp);
+       struct bhv_vfs          *vfsp = XFS_MTOVFS(mp);
 
        for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
                if (mp->m_flags & xfs_infop->flag)
@@ -1967,7 +1973,7 @@ xfs_freeze(
 }
 
 
-vfsops_t xfs_vfsops = {
+bhv_vfsops_t xfs_vfsops = {
        BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS),
        .vfs_parseargs          = xfs_parseargs,
        .vfs_showargs           = xfs_showargs,
index 7027ae68ee38e6491897eb88033886b7c6fb0ea5..00a6b7dc24a0a6ed047999b85f4eeca4f1494d1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -16,8 +16,6 @@
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/capability.h>
-
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_types.h"
@@ -27,7 +25,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
-#include "xfs_dir_leaf.h"
 #include "xfs_itable.h"
 #include "xfs_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_log_priv.h"
 #include "xfs_mac.h"
 
-
-/*
- * The maximum pathlen is 1024 bytes. Since the minimum file system
- * blocksize is 512 bytes, we can get a max of 2 extents back from
- * bmapi.
- */
-#define SYMLINK_MAPS 2
-
-/*
- * For xfs, we check that the file isn't too big to be opened by this kernel.
- * No other open action is required for regular files.  Devices are handled
- * through the specfs file system, pipes through fifofs.  Device and
- * fifo vnodes are "wrapped" by specfs and fifofs vnodes, respectively,
- * when a new vnode is first looked up or created.
- */
 STATIC int
 xfs_open(
        bhv_desc_t      *bdp,
        cred_t          *credp)
 {
        int             mode;
-       vnode_t         *vp;
-       xfs_inode_t     *ip;
-
-       vp = BHV_TO_VNODE(bdp);
-       ip = XFS_BHVTOI(bdp);
+       bhv_vnode_t     *vp = BHV_TO_VNODE(bdp);
+       xfs_inode_t     *ip = XFS_BHVTOI(bdp);
 
        if (XFS_FORCED_SHUTDOWN(ip->i_mount))
                return XFS_ERROR(EIO);
@@ -101,6 +78,35 @@ xfs_open(
        return 0;
 }
 
+STATIC int
+xfs_close(
+       bhv_desc_t      *bdp,
+       int             flags,
+       lastclose_t     lastclose,
+       cred_t          *credp)
+{
+       bhv_vnode_t     *vp = BHV_TO_VNODE(bdp);
+       xfs_inode_t     *ip = XFS_BHVTOI(bdp);
+
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+               return XFS_ERROR(EIO);
+
+       if (lastclose != L_TRUE || !VN_ISREG(vp))
+               return 0;
+
+       /*
+        * If we previously truncated this file and removed old data in
+        * the process, we want to initiate "early" writeout on the last
+        * close.  This is an attempt to combat the notorious NULL files
+        * problem which is particularly noticable from a truncate down,
+        * buffered (re-)write (delalloc), followed by a crash.  What we
+        * are effectively doing here is significantly reducing the time
+        * window where we'd otherwise be exposed to that problem.
+        */
+       if (VUNTRUNCATE(vp) && VN_DIRTY(vp) && ip->i_delayed_blks > 0)
+               return bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE);
+       return 0;
+}
 
 /*
  * xfs_getattr
@@ -108,13 +114,13 @@ xfs_open(
 STATIC int
 xfs_getattr(
        bhv_desc_t      *bdp,
-       vattr_t         *vap,
+       bhv_vattr_t     *vap,
        int             flags,
        cred_t          *credp)
 {
        xfs_inode_t     *ip;
        xfs_mount_t     *mp;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        vp  = BHV_TO_VNODE(bdp);
        vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
@@ -241,7 +247,7 @@ xfs_getattr(
 int
 xfs_setattr(
        bhv_desc_t              *bdp,
-       vattr_t                 *vap,
+       bhv_vattr_t             *vap,
        int                     flags,
        cred_t                  *credp)
 {
@@ -255,7 +261,7 @@ xfs_setattr(
        uid_t                   uid=0, iuid=0;
        gid_t                   gid=0, igid=0;
        int                     timeflags = 0;
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        xfs_prid_t              projid=0, iprojid=0;
        int                     mandlock_before, mandlock_after;
        struct xfs_dquot        *udqp, *gdqp, *olddquot1, *olddquot2;
@@ -347,7 +353,6 @@ xfs_setattr(
         */
        tp = NULL;
        lock_flags = XFS_ILOCK_EXCL;
-       ASSERT(flags & ATTR_NOLOCK ? flags & ATTR_DMI : 1);
        if (flags & ATTR_NOLOCK)
                need_iolock = 0;
        if (!(mask & XFS_AT_SIZE)) {
@@ -666,9 +671,17 @@ xfs_setattr(
                                            ((ip->i_d.di_nlink != 0 ||
                                              !(mp->m_flags & XFS_MOUNT_WSYNC))
                                             ? 1 : 0));
-                       if (code) {
+                       if (code)
                                goto abort_return;
-                       }
+                       /*
+                        * Truncated "down", so we're removing references
+                        * to old data here - if we now delay flushing for
+                        * a long time, we expose ourselves unduly to the
+                        * notorious NULL files problem.  So, we mark this
+                        * vnode and flush it when the file is closed, and
+                        * do not wait the usual (long) time for writeout.
+                        */
+                       VTRUNCATE(vp);
                }
                /*
                 * Have to do this even if the file's size doesn't change.
@@ -800,6 +813,8 @@ xfs_setattr(
                                di_flags |= XFS_DIFLAG_NODUMP;
                        if (vap->va_xflags & XFS_XFLAG_PROJINHERIT)
                                di_flags |= XFS_DIFLAG_PROJINHERIT;
+                       if (vap->va_xflags & XFS_XFLAG_NODEFRAG)
+                               di_flags |= XFS_DIFLAG_NODEFRAG;
                        if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
                                if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
                                        di_flags |= XFS_DIFLAG_RTINHERIT;
@@ -869,7 +884,7 @@ xfs_setattr(
         */
        mandlock_after = MANDLOCK(vp, ip->i_d.di_mode);
        if (mandlock_before != mandlock_after) {
-               VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_ENF_LOCKING,
+               bhv_vop_vnode_change(vp, VCHANGE_FLAGS_ENF_LOCKING,
                                 mandlock_after);
        }
 
@@ -935,6 +950,13 @@ xfs_access(
 }
 
 
+/*
+ * The maximum pathlen is 1024 bytes. Since the minimum file system
+ * blocksize is 512 bytes, we can get a max of 2 extents back from
+ * bmapi.
+ */
+#define SYMLINK_MAPS 2
+
 /*
  * xfs_readlink
  *
@@ -950,7 +972,7 @@ xfs_readlink(
        int             count;
        xfs_off_t       offset;
        int             pathlen;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
        int             error = 0;
        xfs_mount_t     *mp;
        int             nmaps;
@@ -1000,7 +1022,7 @@ xfs_readlink(
                nmaps = SYMLINK_MAPS;
 
                error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen),
-                                 0, NULL, 0, mval, &nmaps, NULL);
+                                 0, NULL, 0, mval, &nmaps, NULL, NULL);
 
                if (error) {
                        goto error_return;
@@ -1208,8 +1230,8 @@ xfs_inactive_free_eofblocks(
 
        nimaps = 1;
        xfs_ilock(ip, XFS_ILOCK_SHARED);
-       error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0,
-                         NULL, 0, &imap, &nimaps, NULL);
+       error = XFS_BMAPI(mp, NULL, &ip->i_iocore, end_fsb, map_len, 0,
+                         NULL, 0, &imap, &nimaps, NULL, NULL);
        xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
        if (!error && (nimaps != 0) &&
@@ -1338,7 +1360,7 @@ xfs_inactive_symlink_rmt(
        nmaps = ARRAY_SIZE(mval);
        if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size),
                        XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps,
-                       &free_list)))
+                       &free_list, NULL)))
                goto error0;
        /*
         * Invalidate the block(s).
@@ -1353,7 +1375,7 @@ xfs_inactive_symlink_rmt(
         * Unmap the dead block(s) to the free_list.
         */
        if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
-                       &first_block, &free_list, &done)))
+                       &first_block, &free_list, NULL, &done)))
                goto error1;
        ASSERT(done);
        /*
@@ -1469,9 +1491,6 @@ xfs_inactive_symlink_local(
        return 0;
 }
 
-/*
- *
- */
 STATIC int
 xfs_inactive_attrs(
        xfs_inode_t     *ip,
@@ -1524,16 +1543,16 @@ xfs_release(
        bhv_desc_t      *bdp)
 {
        xfs_inode_t     *ip;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
        xfs_mount_t     *mp;
        int             error;
 
        vp = BHV_TO_VNODE(bdp);
        ip = XFS_BHVTOI(bdp);
+       mp = ip->i_mount;
 
-       if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) {
+       if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0))
                return 0;
-       }
 
        /* If this is a read-only mount, don't do this (would generate I/O) */
        if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
@@ -1545,8 +1564,6 @@ xfs_release(
                return 0;
 #endif
 
-       mp = ip->i_mount;
-
        if (ip->i_d.di_nlink != 0) {
                if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
                     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 ||
@@ -1579,8 +1596,8 @@ xfs_inactive(
        cred_t          *credp)
 {
        xfs_inode_t     *ip;
-       vnode_t         *vp;
-       xfs_bmap_free_t free_list; 
+       bhv_vnode_t     *vp;
+       xfs_bmap_free_t free_list;
        xfs_fsblock_t   first_block;
        int             committed;
        xfs_trans_t     *tp;
@@ -1760,7 +1777,7 @@ xfs_inactive(
                        cmn_err(CE_NOTE,
                "xfs_inactive:  xfs_ifree() returned an error = %d on %s",
                                error, mp->m_fsname);
-                       xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+                       xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
                }
                xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
        } else {
@@ -1795,17 +1812,17 @@ xfs_inactive(
 STATIC int
 xfs_lookup(
        bhv_desc_t              *dir_bdp,
-       vname_t                 *dentry,
-       vnode_t                 **vpp,
+       bhv_vname_t             *dentry,
+       bhv_vnode_t             **vpp,
        int                     flags,
-       vnode_t                 *rdir,
+       bhv_vnode_t             *rdir,
        cred_t                  *credp)
 {
        xfs_inode_t             *dp, *ip;
        xfs_ino_t               e_inum;
        int                     error;
        uint                    lock_mode;
-       vnode_t                 *dir_vp;
+       bhv_vnode_t             *dir_vp;
 
        dir_vp = BHV_TO_VNODE(dir_bdp);
        vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address);
@@ -1832,15 +1849,15 @@ xfs_lookup(
 STATIC int
 xfs_create(
        bhv_desc_t              *dir_bdp,
-       vname_t                 *dentry,
-       vattr_t                 *vap,
-       vnode_t                 **vpp,
+       bhv_vname_t             *dentry,
+       bhv_vattr_t             *vap,
+       bhv_vnode_t             **vpp,
        cred_t                  *credp)
 {
        char                    *name = VNAME(dentry);
-       vnode_t                 *dir_vp;
+       bhv_vnode_t             *dir_vp;
        xfs_inode_t             *dp, *ip;
-       vnode_t                 *vp=NULL;
+       bhv_vnode_t             *vp = NULL;
        xfs_trans_t             *tp;
        xfs_mount_t             *mp;
        xfs_dev_t               rdev;
@@ -1938,8 +1955,7 @@ xfs_create(
        if (error)
                goto error_return;
 
-       if (resblks == 0 &&
-           (error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen)))
+       if (resblks == 0 && (error = xfs_dir_canenter(tp, dp, name, namelen)))
                goto error_return;
        rdev = (vap->va_mask & XFS_AT_RDEV) ? vap->va_rdev : 0;
        error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 1,
@@ -1970,9 +1986,9 @@ xfs_create(
        xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
        dp_joined_to_trans = B_TRUE;
 
-       error = XFS_DIR_CREATENAME(mp, tp, dp, name, namelen, ip->i_ino,
-               &first_block, &free_list,
-               resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+       error = xfs_dir_createname(tp, dp, name, namelen, ip->i_ino,
+                                       &first_block, &free_list, resblks ?
+                                       resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
        if (error) {
                ASSERT(error != ENOSPC);
                goto abort_return;
@@ -2026,7 +2042,7 @@ xfs_create(
         * Propagate the fact that the vnode changed after the
         * xfs_inode locks have been released.
         */
-       VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_TRUNCATED, 3);
+       bhv_vop_vnode_change(vp, VCHANGE_FLAGS_TRUNCATED, 3);
 
        *vpp = vp;
 
@@ -2107,7 +2123,7 @@ int xfs_rm_attempts;
 STATIC int
 xfs_lock_dir_and_entry(
        xfs_inode_t     *dp,
-       vname_t         *dentry,
+       bhv_vname_t     *dentry,
        xfs_inode_t     *ip)    /* inode of entry 'name' */
 {
        int             attempts;
@@ -2321,10 +2337,10 @@ int remove_which_error_return = 0;
 STATIC int
 xfs_remove(
        bhv_desc_t              *dir_bdp,
-       vname_t                 *dentry,
+       bhv_vname_t             *dentry,
        cred_t                  *credp)
 {
-       vnode_t                 *dir_vp;
+       bhv_vnode_t             *dir_vp;
        char                    *name = VNAME(dentry);
        xfs_inode_t             *dp, *ip;
        xfs_trans_t             *tp = NULL;
@@ -2448,8 +2464,8 @@ xfs_remove(
         * Entry must exist since we did a lookup in xfs_lock_dir_and_entry.
         */
        XFS_BMAP_INIT(&free_list, &first_block);
-       error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, ip->i_ino,
-               &first_block, &free_list, 0);
+       error = xfs_dir_removename(tp, dp, name, namelen, ip->i_ino,
+                                       &first_block, &free_list, 0);
        if (error) {
                ASSERT(error != ENOENT);
                REMOVE_DEBUG_TRACE(__LINE__);
@@ -2511,7 +2527,7 @@ xfs_remove(
        /*
         * Let interposed file systems know about removed links.
         */
-       VOP_LINK_REMOVED(XFS_ITOV(ip), dir_vp, link_zero);
+       bhv_vop_link_removed(XFS_ITOV(ip), dir_vp, link_zero);
 
        IRELE(ip);
 
@@ -2564,8 +2580,8 @@ xfs_remove(
 STATIC int
 xfs_link(
        bhv_desc_t              *target_dir_bdp,
-       vnode_t                 *src_vp,
-       vname_t                 *dentry,
+       bhv_vnode_t             *src_vp,
+       bhv_vname_t             *dentry,
        cred_t                  *credp)
 {
        xfs_inode_t             *tdp, *sip;
@@ -2577,7 +2593,7 @@ xfs_link(
        xfs_fsblock_t           first_block;
        int                     cancel_flags;
        int                     committed;
-       vnode_t                 *target_dir_vp;
+       bhv_vnode_t             *target_dir_vp;
        int                     resblks;
        char                    *target_name = VNAME(dentry);
        int                     target_namelen;
@@ -2668,13 +2684,12 @@ xfs_link(
        }
 
        if (resblks == 0 &&
-           (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name,
-                       target_namelen)))
+           (error = xfs_dir_canenter(tp, tdp, target_name, target_namelen)))
                goto error_return;
 
        XFS_BMAP_INIT(&free_list, &first_block);
 
-       error = XFS_DIR_CREATENAME(mp, tp, tdp, target_name, target_namelen,
+       error = xfs_dir_createname(tp, tdp, target_name, target_namelen,
                                   sip->i_ino, &first_block, &free_list,
                                   resblks);
        if (error)
@@ -2734,15 +2749,15 @@ std_return:
 STATIC int
 xfs_mkdir(
        bhv_desc_t              *dir_bdp,
-       vname_t                 *dentry,
-       vattr_t                 *vap,
-       vnode_t                 **vpp,
+       bhv_vname_t             *dentry,
+       bhv_vattr_t             *vap,
+       bhv_vnode_t             **vpp,
        cred_t                  *credp)
 {
        char                    *dir_name = VNAME(dentry);
        xfs_inode_t             *dp;
        xfs_inode_t             *cdp;   /* inode of created dir */
-       vnode_t                 *cvp;   /* vnode of created dir */
+       bhv_vnode_t             *cvp;   /* vnode of created dir */
        xfs_trans_t             *tp;
        xfs_mount_t             *mp;
        int                     cancel_flags;
@@ -2750,7 +2765,7 @@ xfs_mkdir(
        int                     committed;
        xfs_bmap_free_t         free_list;
        xfs_fsblock_t           first_block;
-       vnode_t                 *dir_vp;
+       bhv_vnode_t             *dir_vp;
        boolean_t               dp_joined_to_trans;
        boolean_t               created = B_FALSE;
        int                     dm_event_sent = 0;
@@ -2840,7 +2855,7 @@ xfs_mkdir(
                goto error_return;
 
        if (resblks == 0 &&
-           (error = XFS_DIR_CANENTER(mp, tp, dp, dir_name, dir_namelen)))
+           (error = xfs_dir_canenter(tp, dp, dir_name, dir_namelen)))
                goto error_return;
        /*
         * create the directory inode.
@@ -2867,9 +2882,9 @@ xfs_mkdir(
 
        XFS_BMAP_INIT(&free_list, &first_block);
 
-       error = XFS_DIR_CREATENAME(mp, tp, dp, dir_name, dir_namelen,
-                       cdp->i_ino, &first_block, &free_list,
-                       resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+       error = xfs_dir_createname(tp, dp, dir_name, dir_namelen, cdp->i_ino,
+                                  &first_block, &free_list, resblks ?
+                                  resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
        if (error) {
                ASSERT(error != ENOSPC);
                goto error1;
@@ -2883,16 +2898,14 @@ xfs_mkdir(
         */
        dp->i_gen++;
 
-       error = XFS_DIR_INIT(mp, tp, cdp, dp);
-       if (error) {
+       error = xfs_dir_init(tp, cdp, dp);
+       if (error)
                goto error2;
-       }
 
        cdp->i_gen = 1;
        error = xfs_bumplink(tp, dp);
-       if (error) {
+       if (error)
                goto error2;
-       }
 
        cvp = XFS_ITOV(cdp);
 
@@ -2969,7 +2982,7 @@ std_return:
 STATIC int
 xfs_rmdir(
        bhv_desc_t              *dir_bdp,
-       vname_t                 *dentry,
+       bhv_vname_t             *dentry,
        cred_t                  *credp)
 {
        char                    *name = VNAME(dentry);
@@ -2982,7 +2995,7 @@ xfs_rmdir(
        xfs_fsblock_t           first_block;
        int                     cancel_flags;
        int                     committed;
-       vnode_t                 *dir_vp;
+       bhv_vnode_t             *dir_vp;
        int                     dm_di_mode = 0;
        int                     last_cdp_link;
        int                     namelen;
@@ -3101,16 +3114,15 @@ xfs_rmdir(
                error = XFS_ERROR(ENOTEMPTY);
                goto error_return;
        }
-       if (!XFS_DIR_ISEMPTY(mp, cdp)) {
+       if (!xfs_dir_isempty(cdp)) {
                error = XFS_ERROR(ENOTEMPTY);
                goto error_return;
        }
 
-       error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, cdp->i_ino,
-               &first_block, &free_list, resblks);
-       if (error) {
+       error = xfs_dir_removename(tp, dp, name, namelen, cdp->i_ino,
+                                       &first_block, &free_list, resblks);
+       if (error)
                goto error1;
-       }
 
        xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
@@ -3181,7 +3193,7 @@ xfs_rmdir(
        /*
         * Let interposed file systems know about removed links.
         */
-       VOP_LINK_REMOVED(XFS_ITOV(cdp), dir_vp, last_cdp_link);
+       bhv_vop_link_removed(XFS_ITOV(cdp), dir_vp, last_cdp_link);
 
        IRELE(cdp);
 
@@ -3209,8 +3221,6 @@ xfs_rmdir(
 
 
 /*
- * xfs_readdir
- *
  * Read dp's entries starting at uiop->uio_offset and translate them into
  * bufsize bytes worth of struct dirents starting at bufbase.
  */
@@ -3230,28 +3240,23 @@ xfs_readdir(
                                               (inst_t *)__return_address);
        dp = XFS_BHVTOI(dir_bdp);
 
-       if (XFS_FORCED_SHUTDOWN(dp->i_mount)) {
+       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
                return XFS_ERROR(EIO);
-       }
 
        lock_mode = xfs_ilock_map_shared(dp);
-       error = XFS_DIR_GETDENTS(dp->i_mount, tp, dp, uiop, eofp);
+       error = xfs_dir_getdents(tp, dp, uiop, eofp);
        xfs_iunlock_map_shared(dp, lock_mode);
        return error;
 }
 
 
-/*
- * xfs_symlink
- *
- */
 STATIC int
 xfs_symlink(
        bhv_desc_t              *dir_bdp,
-       vname_t                 *dentry,
-       vattr_t                 *vap,
+       bhv_vname_t             *dentry,
+       bhv_vattr_t             *vap,
        char                    *target_path,
-       vnode_t                 **vpp,
+       bhv_vnode_t             **vpp,
        cred_t                  *credp)
 {
        xfs_trans_t             *tp;
@@ -3263,7 +3268,7 @@ xfs_symlink(
        xfs_bmap_free_t         free_list;
        xfs_fsblock_t           first_block;
        boolean_t               dp_joined_to_trans;
-       vnode_t                 *dir_vp;
+       bhv_vnode_t             *dir_vp;
        uint                    cancel_flags;
        int                     committed;
        xfs_fileoff_t           first_fsb;
@@ -3308,7 +3313,7 @@ xfs_symlink(
                int len, total;
                char *path;
 
-               for(total = 0, path = target_path; total < pathlen;) {
+               for (total = 0, path = target_path; total < pathlen;) {
                        /*
                         * Skip any slashes.
                         */
@@ -3402,7 +3407,7 @@ xfs_symlink(
         * Check for ability to enter directory entry, if no space reserved.
         */
        if (resblks == 0 &&
-           (error = XFS_DIR_CANENTER(mp, tp, dp, link_name, link_namelen)))
+           (error = xfs_dir_canenter(tp, dp, link_name, link_namelen)))
                goto error_return;
        /*
         * Initialize the bmap freelist prior to calling either
@@ -3457,7 +3462,7 @@ xfs_symlink(
                error = xfs_bmapi(tp, ip, first_fsb, fs_blocks,
                                  XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
                                  &first_block, resblks, mval, &nmaps,
-                                 &free_list);
+                                 &free_list, NULL);
                if (error) {
                        goto error1;
                }
@@ -3489,11 +3494,10 @@ xfs_symlink(
        /*
         * Create the directory entry for the symlink.
         */
-       error = XFS_DIR_CREATENAME(mp, tp, dp, link_name, link_namelen,
-                       ip->i_ino, &first_block, &free_list, resblks);
-       if (error) {
+       error = xfs_dir_createname(tp, dp, link_name, link_namelen, ip->i_ino,
+                                  &first_block, &free_list, resblks);
+       if (error)
                goto error1;
-       }
        xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
@@ -3541,7 +3545,7 @@ std_return:
        }
 
        if (!error) {
-               vnode_t *vp;
+               bhv_vnode_t *vp;
 
                ASSERT(ip);
                vp = XFS_ITOV(ip);
@@ -3606,10 +3610,10 @@ xfs_fid2(
 int
 xfs_rwlock(
        bhv_desc_t      *bdp,
-       vrwlock_t       locktype)
+       bhv_vrwlock_t   locktype)
 {
        xfs_inode_t     *ip;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        vp = BHV_TO_VNODE(bdp);
        if (VN_ISDIR(vp))
@@ -3637,10 +3641,10 @@ xfs_rwlock(
 void
 xfs_rwunlock(
        bhv_desc_t      *bdp,
-       vrwlock_t       locktype)
+       bhv_vrwlock_t   locktype)
 {
        xfs_inode_t     *ip;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        vp = BHV_TO_VNODE(bdp);
        if (VN_ISDIR(vp))
@@ -3744,7 +3748,6 @@ xfs_inode_flush(
        return error;
 }
 
-
 int
 xfs_set_dmattrs (
        bhv_desc_t      *bdp,
@@ -3785,16 +3788,12 @@ xfs_set_dmattrs (
        return error;
 }
 
-
-/*
- * xfs_reclaim
- */
 STATIC int
 xfs_reclaim(
        bhv_desc_t      *bdp)
 {
        xfs_inode_t     *ip;
-       vnode_t         *vp;
+       bhv_vnode_t     *vp;
 
        vp = BHV_TO_VNODE(bdp);
        ip = XFS_BHVTOI(bdp);
@@ -3849,7 +3848,7 @@ xfs_finish_reclaim(
        int             sync_mode)
 {
        xfs_ihash_t     *ih = ip->i_hash;
-       vnode_t         *vp = XFS_ITOV_NULL(ip);
+       bhv_vnode_t     *vp = XFS_ITOV_NULL(ip);
        int             error;
 
        if (vp && VN_BAD(vp))
@@ -4116,10 +4115,10 @@ retry:
                 * Issue the xfs_bmapi() call to allocate the blocks
                 */
                XFS_BMAP_INIT(&free_list, &firstfsb);
-               error = xfs_bmapi(tp, ip, startoffset_fsb,
+               error = XFS_BMAPI(mp, tp, &ip->i_iocore, startoffset_fsb,
                                  allocatesize_fsb, bmapi_flag,
                                  &firstfsb, 0, imapp, &nimaps,
-                                 &free_list);
+                                 &free_list, NULL);
                if (error) {
                        goto error0;
                }
@@ -4199,8 +4198,8 @@ xfs_zero_remaining_bytes(
        for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
                offset_fsb = XFS_B_TO_FSBT(mp, offset);
                nimap = 1;
-               error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, NULL, 0, &imap,
-                       &nimap, NULL);
+               error = XFS_BMAPI(mp, NULL, &ip->i_iocore, offset_fsb, 1, 0,
+                       NULL, 0, &imap, &nimap, NULL, NULL);
                if (error || nimap < 1)
                        break;
                ASSERT(imap.br_blockcount >= 1);
@@ -4259,7 +4258,7 @@ xfs_free_file_space(
        xfs_off_t               len,
        int                     attr_flags)
 {
-       vnode_t                 *vp;
+       bhv_vnode_t             *vp;
        int                     committed;
        int                     done;
        xfs_off_t               end_dmi_offset;
@@ -4308,7 +4307,6 @@ xfs_free_file_space(
                        return error;
        }
 
-       ASSERT(attr_flags & ATTR_NOLOCK ? attr_flags & ATTR_DMI : 1);
        if (attr_flags & ATTR_NOLOCK)
                need_iolock = 0;
        if (need_iolock) {
@@ -4326,7 +4324,7 @@ xfs_free_file_space(
        if (VN_CACHED(vp) != 0) {
                xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1,
                                ctooff(offtoct(ioffset)), -1);
-               VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(ioffset)),
+               bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)),
                                -1, FI_REMAPF_LOCKED);
        }
 
@@ -4338,8 +4336,8 @@ xfs_free_file_space(
         */
        if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) {
                nimap = 1;
-               error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0,
-                       &imap, &nimap, NULL);
+               error = XFS_BMAPI(mp, NULL, &ip->i_iocore, startoffset_fsb,
+                       1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -4353,8 +4351,8 @@ xfs_free_file_space(
                                startoffset_fsb += mp->m_sb.sb_rextsize - mod;
                }
                nimap = 1;
-               error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0,
-                       &imap, &nimap, NULL);
+               error = XFS_BMAPI(mp, NULL, &ip->i_iocore, endoffset_fsb - 1,
+                       1, 0, NULL, 0, &imap, &nimap, NULL, NULL);
                if (error)
                        goto out_unlock_iolock;
                ASSERT(nimap == 0 || nimap == 1);
@@ -4426,9 +4424,9 @@ xfs_free_file_space(
                 * issue the bunmapi() call to free the blocks
                 */
                XFS_BMAP_INIT(&free_list, &firstfsb);
-               error = xfs_bunmapi(tp, ip, startoffset_fsb,
+               error = XFS_BUNMAPI(mp, tp, &ip->i_iocore, startoffset_fsb,
                                  endoffset_fsb - startoffset_fsb,
-                                 0, 2, &firstfsb, &free_list, &done);
+                                 0, 2, &firstfsb, &free_list, NULL, &done);
                if (error) {
                        goto error0;
                }
@@ -4488,8 +4486,8 @@ xfs_change_file_space(
        xfs_off_t       startoffset;
        xfs_off_t       llen;
        xfs_trans_t     *tp;
-       vattr_t         va;
-       vnode_t         *vp;
+       bhv_vattr_t     va;
+       bhv_vnode_t     *vp;
 
        vp = BHV_TO_VNODE(bdp);
        vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
@@ -4642,9 +4640,10 @@ xfs_change_file_space(
        return error;
 }
 
-vnodeops_t xfs_vnodeops = {
+bhv_vnodeops_t xfs_vnodeops = {
        BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_XFS),
        .vop_open               = xfs_open,
+       .vop_close              = xfs_close,
        .vop_read               = xfs_read,
 #ifdef HAVE_SENDFILE
        .vop_sendfile           = xfs_sendfile,
index 8ca4f6b2da19e87af861971b23b7b1c4778014e5..ed06f59b544d4c7c84ef7ccdb20ab56fa1444554 100644 (file)
@@ -46,6 +46,6 @@ extern void scr_memcpyw(u16 *d, const u16 *s, unsigned int count);
 #define vga_readb(a)   readb((u8 __iomem *)(a))
 #define vga_writeb(v,a)        writeb(v, (u8 __iomem *)(a))
 
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap(x, 0))
+#define VGA_MAP_MEM(x,s)       ((unsigned long) ioremap(x, s))
 
 #endif
index 926e5ee128e92cdbdc91e6f5bda075cf06186014..1e0b913c3d71ce9be96847b128b3965da2672f21 100644 (file)
@@ -4,7 +4,7 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 
-#define VGA_MAP_MEM(x) (PCIMEM_BASE + (x))
+#define VGA_MAP_MEM(x,s)       (PCIMEM_BASE + (x))
 
 #define vga_readb(x)   (*((volatile unsigned char *)x))
 #define vga_writeb(x,y)        (*((volatile unsigned char *)y) = (x))
index ef0c0e50cc951e898ea4f50661db2e4f1dc551fa..0ecf68ac03aa95c312a15876473d5df5a8851301 100644 (file)
@@ -12,7 +12,7 @@
  *     access the videoram directly without any black magic.
  */
 
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
 
 #define vga_readb(x) (*(x))
 #define vga_writeb(x,y) (*(y) = (x))
index 091177cda223708f6c0a3560b58bfe775845f02a..02184ecd820822af282794071456ebba12502c07 100644 (file)
@@ -17,7 +17,7 @@
 extern unsigned long vga_console_iobase;
 extern unsigned long vga_console_membase;
 
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap_nocache(vga_console_membase + (x), 0))
+#define VGA_MAP_MEM(x,s)       ((unsigned long) ioremap_nocache(vga_console_membase + (x), s))
 
 #define vga_readb(x)   (*(x))
 #define vga_writeb(x,y)        (*(y) = (x))
index d0f4b6eed7a34f0c234200ec0cb3ab81297964d7..533163447cc9d3f711d256c144bb6095b982b0f9 100644 (file)
@@ -14,7 +14,7 @@
  *     access the videoram directly without any black magic.
  */
 
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
 
 #define vga_readb(x) (*(x))
 #define vga_writeb(x,y) (*(y) = (x))
index 34755c0a63988e21121a33c943fbada2234bb7da..c1dd0b10bc2737ba1abb23434106b5560b78924f 100644 (file)
@@ -13,7 +13,7 @@
  *     access the videoram directly without any black magic.
  */
 
-#define VGA_MAP_MEM(x) (0xb0000000L + (unsigned long)(x))
+#define VGA_MAP_MEM(x,s)       (0xb0000000L + (unsigned long)(x))
 
 #define vga_readb(x)   (*(x))
 #define vga_writeb(x,y)        (*(y) = (x))
index eadaf2f3d03255c0eefe558138a943894cecdaf1..a2eac409c1ec2cbcd81ce48ced5b07aac04195a0 100644 (file)
@@ -41,9 +41,9 @@ static inline u16 scr_readw(volatile const u16 *addr)
 extern unsigned long vgacon_remap_base;
 
 #ifdef __powerpc64__
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0))
+#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s))
 #else
-#define VGA_MAP_MEM(x) (x + vgacon_remap_base)
+#define VGA_MAP_MEM(x,s) (x + vgacon_remap_base)
 #endif
 
 #define vga_readb(x) (*(x))
index 9c57eb363b40466582d127da68f0025bac7c380f..c69d5b2ba19a488ea3abf8a75c25383edd13d562 100644 (file)
@@ -28,6 +28,6 @@ static inline u16 scr_readw(const u16 *addr)
        return *addr;
 }
 
-#define VGA_MAP_MEM(x) (x)
+#define VGA_MAP_MEM(x,s) (x)
 
 #endif
index ef0c0e50cc951e898ea4f50661db2e4f1dc551fa..0ecf68ac03aa95c312a15876473d5df5a8851301 100644 (file)
@@ -12,7 +12,7 @@
  *     access the videoram directly without any black magic.
  */
 
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
 
 #define vga_readb(x) (*(x))
 #define vga_writeb(x,y) (*(y) = (x))
index 23d82f6acb572b77971e33b379ab34ea6627c8cf..1fd8cab3a297fb1446fe5081048ca737a402e900 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _XTENSA_VGA_H
 #define _XTENSA_VGA_H
 
-#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+#define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x)
 
 #define vga_readb(x)   (*(x))
 #define vga_writeb(x,y)        (*(y) = (x))
index 836325ee0931eef5398a304766217cc4388589f8..46d0e079735d19c01310df7200f058dd36af1401 100644 (file)
@@ -217,7 +217,7 @@ extern struct dentry * d_alloc_anon(struct inode *);
 extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
-extern void shrink_dcache_anon(struct hlist_head *);
+extern void shrink_dcache_anon(struct super_block *);
 extern int d_invalidate(struct dentry *);
 
 /* only used at mount-time */
index b2e5da2b637ba0b5db4775dabc3ec9de24dff3e9..1e5f30da98bc528b9ab9aaf629a673cb50e6f8ae 100644 (file)
@@ -60,11 +60,6 @@ extern void bus_unregister(struct bus_type * bus);
 
 extern void bus_rescan_devices(struct bus_type * bus);
 
-extern struct bus_type * get_bus(struct bus_type * bus);
-extern void put_bus(struct bus_type * bus);
-
-extern struct bus_type * find_bus(char * name);
-
 /* iterator helpers for buses */
 
 int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
@@ -147,6 +142,7 @@ struct class {
 
        struct subsystem        subsys;
        struct list_head        children;
+       struct list_head        devices;
        struct list_head        interfaces;
        struct semaphore        sem;    /* locks both the children and interfaces lists */
 
@@ -163,9 +159,6 @@ struct class {
 extern int class_register(struct class *);
 extern void class_unregister(struct class *);
 
-extern struct class * class_get(struct class *);
-extern void class_put(struct class *);
-
 
 struct class_attribute {
        struct attribute        attr;
@@ -313,6 +306,7 @@ struct device {
        struct kobject kobj;
        char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
        struct device_attribute uevent_attr;
+       struct device_attribute *devt_attr;
 
        struct semaphore        sem;    /* semaphore to synchronize calls to
                                         * its driver.
@@ -340,6 +334,11 @@ struct device {
        struct dma_coherent_mem *dma_mem; /* internal for coherent mem
                                             override */
 
+       /* class_device migration path */
+       struct list_head        node;
+       struct class            *class;         /* optional*/
+       dev_t                   devt;           /* dev_t, creates the sysfs "dev" */
+
        void    (*release)(struct device * dev);
 };
 
@@ -381,6 +380,13 @@ extern int  device_attach(struct device * dev);
 extern void driver_attach(struct device_driver * drv);
 extern void device_reprobe(struct device *dev);
 
+/*
+ * Easy functions for dynamically creating devices on the fly
+ */
+extern struct device *device_create(struct class *cls, struct device *parent,
+                                   dev_t devt, char *fmt, ...)
+                                   __attribute__((format(printf,4,5)));
+extern void device_destroy(struct class *cls, dev_t devt);
 
 /*
  * Platform "fixup" functions - allow the platform to have their say
@@ -410,8 +416,9 @@ extern int firmware_register(struct subsystem *);
 extern void firmware_unregister(struct subsystem *);
 
 /* debugging and troubleshooting/diagnostic helpers. */
+extern const char *dev_driver_string(struct device *dev);
 #define dev_printk(level, dev, format, arg...) \
-       printk(level "%s %s: " format , (dev)->driver ? (dev)->driver->name : "" , (dev)->bus_id , ## arg)
+       printk(level "%s %s: " format , dev_driver_string(dev) , (dev)->bus_id , ## arg)
 
 #ifdef DEBUG
 #define dev_dbg(dev, format, arg...)           \
index ecc8c2c3d8ca8382d5b121c7219d9f73b33baba4..73c7d6f04b31a657a9b7060ac43f5a256ce070f4 100644 (file)
@@ -782,7 +782,6 @@ extern int setlease(struct file *, long, struct file_lock **);
 extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
-extern void steal_locks(fl_owner_t from);
 
 struct fasync_struct {
        int     magic;
diff --git a/include/linux/isa.h b/include/linux/isa.h
new file mode 100644 (file)
index 0000000..1b85533
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * ISA bus.
+ */
+
+#ifndef __LINUX_ISA_H
+#define __LINUX_ISA_H
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+struct isa_driver {
+       int (*match)(struct device *, unsigned int);
+       int (*probe)(struct device *, unsigned int);
+       int (*remove)(struct device *, unsigned int);
+       void (*shutdown)(struct device *, unsigned int);
+       int (*suspend)(struct device *, unsigned int, pm_message_t);
+       int (*resume)(struct device *, unsigned int);
+
+       struct device_driver driver;
+       struct device *devices;
+};
+
+#define to_isa_driver(x) container_of((x), struct isa_driver, driver)
+
+int isa_register_driver(struct isa_driver *, unsigned int);
+void isa_unregister_driver(struct isa_driver *);
+
+#endif /* __LINUX_ISA_H */
index cbf464ad9589526d139b369ea3c00f5b920348c9..e81ebf910d0bc3d9b1b38732f59947f1270ba99e 100644 (file)
@@ -205,6 +205,11 @@ struct key_type {
        /* match a key against a description */
        int (*match)(const struct key *key, const void *desc);
 
+       /* clear some of the data from a key on revokation (optional)
+        * - the key's semaphore will be write-locked by the caller
+        */
+       void (*revoke)(struct key *key);
+
        /* clear the data from a key (optional) */
        void (*destroy)(struct key *key);
 
@@ -241,8 +246,9 @@ extern void unregister_key_type(struct key_type *ktype);
 
 extern struct key *key_alloc(struct key_type *type,
                             const char *desc,
-                            uid_t uid, gid_t gid, key_perm_t perm,
-                            int not_in_quota);
+                            uid_t uid, gid_t gid,
+                            struct task_struct *ctx,
+                            key_perm_t perm, int not_in_quota);
 extern int key_payload_reserve(struct key *key, size_t datalen);
 extern int key_instantiate_and_link(struct key *key,
                                    const void *data,
@@ -292,7 +298,9 @@ extern int key_unlink(struct key *keyring,
                      struct key *key);
 
 extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
-                                int not_in_quota, struct key *dest);
+                                struct task_struct *ctx,
+                                int not_in_quota,
+                                struct key *dest);
 
 extern int keyring_clear(struct key *keyring);
 
@@ -313,7 +321,8 @@ extern void keyring_replace_payload(struct key *key, void *replacement);
  * the userspace interface
  */
 extern struct key root_user_keyring, root_session_keyring;
-extern int alloc_uid_keyring(struct user_struct *user);
+extern int alloc_uid_keyring(struct user_struct *user,
+                            struct task_struct *ctx);
 extern void switch_uid_keyring(struct user_struct *new_user);
 extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
 extern int copy_thread_group_keys(struct task_struct *tsk);
@@ -342,7 +351,7 @@ extern void key_init(void);
 #define make_key_ref(k)                        ({ NULL; })
 #define key_ref_to_ptr(k)              ({ NULL; })
 #define is_key_possessed(k)            0
-#define alloc_uid_keyring(u)           0
+#define alloc_uid_keyring(u,c)         0
 #define switch_uid_keyring(u)          do { } while(0)
 #define __install_session_keyring(t, k)        ({ NULL; })
 #define copy_keys(f,t)                 0
@@ -355,6 +364,10 @@ extern void key_init(void);
 #define key_fsgid_changed(t)           do { } while(0)
 #define key_init()                     do { } while(0)
 
+/* Initial keyrings */
+extern struct key root_user_keyring;
+extern struct key root_session_keyring;
+
 #endif /* CONFIG_KEYS */
 #endif /* __KERNEL__ */
 #endif /* _LINUX_KEY_H */
index c187c53cecd0f94dd15bf3340b87c9a3652ea6d3..2d229327959ed9809042af03c8fdb917913e000e 100644 (file)
@@ -190,6 +190,8 @@ struct subsystem _varname##_subsys = { \
 
 /* The global /sys/kernel/ subsystem for people to chain off of */
 extern struct subsystem kernel_subsys;
+/* The global /sys/hypervisor/ subsystem  */
+extern struct subsystem hypervisor_subsys;
 
 /**
  * Helpers for setting the kset of registered objects.
index 4dfb1b84a9b3bef236ef041b3005692462d7b51b..47722d3555320a5a5aedaa14c6feed63deacdb57 100644 (file)
@@ -1313,7 +1313,7 @@ struct security_operations {
 
        /* key management security hooks */
 #ifdef CONFIG_KEYS
-       int (*key_alloc)(struct key *key);
+       int (*key_alloc)(struct key *key, struct task_struct *tsk);
        void (*key_free)(struct key *key);
        int (*key_permission)(key_ref_t key_ref,
                              struct task_struct *context,
@@ -3008,9 +3008,10 @@ static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid
 
 #ifdef CONFIG_KEYS
 #ifdef CONFIG_SECURITY
-static inline int security_key_alloc(struct key *key)
+static inline int security_key_alloc(struct key *key,
+                                    struct task_struct *tsk)
 {
-       return security_ops->key_alloc(key);
+       return security_ops->key_alloc(key, tsk);
 }
 
 static inline void security_key_free(struct key *key)
@@ -3027,7 +3028,8 @@ static inline int security_key_permission(key_ref_t key_ref,
 
 #else
 
-static inline int security_key_alloc(struct key *key)
+static inline int security_key_alloc(struct key *key,
+                                    struct task_struct *tsk)
 {
        return 0;
 }
index 2a4b432e117645cf749782a218afc8c32fdf7262..166a2e58c2871da6dc0de55a3498ae075f869b65 100644 (file)
@@ -37,11 +37,27 @@ struct sysdev_class {
        struct kset             kset;
 };
 
+struct sysdev_class_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct sysdev_class *, char *);
+       ssize_t (*store)(struct sysdev_class *, const char *, size_t);
+};
+
+#define SYSDEV_CLASS_ATTR(_name,_mode,_show,_store)            \
+struct sysdev_class_attribute attr_##_name = {                         \
+       .attr = {.name = __stringify(_name), .mode = _mode },   \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+};
+
 
 extern int sysdev_class_register(struct sysdev_class *);
 extern void sysdev_class_unregister(struct sysdev_class *);
 
-
+extern int sysdev_class_create_file(struct sysdev_class *,
+       struct sysdev_class_attribute *);
+extern void sysdev_class_remove_file(struct sysdev_class *,
+       struct sysdev_class_attribute *);
 /**
  * Auxillary system device drivers.
  */
index e898eeb94166ceff151ffbcb5d88b39babeeb52b..cb35ca50a0a66feffff3a63b598634efc9f1f027 100644 (file)
@@ -290,7 +290,9 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
 extern int tty_register_driver(struct tty_driver *driver);
 extern int tty_unregister_driver(struct tty_driver *driver);
-extern void tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev);
+extern struct class_device *tty_register_device(struct tty_driver *driver,
+                                               unsigned index,
+                                               struct device *dev);
 extern void tty_unregister_device(struct tty_driver *driver, unsigned index);
 extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
                             int buflen);
index 1f492c0c704743a9c1fbada54d482366f8fad911..8dead32e7ebf1065b1268f6b2d25ad781f35bd15 100644 (file)
@@ -40,6 +40,8 @@ struct usb_driver;
  * Devices may also have class-specific or vendor-specific descriptors.
  */
 
+struct ep_device;
+
 /**
  * struct usb_host_endpoint - host-side endpoint descriptor and queue
  * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
@@ -57,7 +59,7 @@ struct usb_host_endpoint {
        struct usb_endpoint_descriptor  desc;
        struct list_head                urb_list;
        void                            *hcpriv;
-       struct kobject                  *kobj;  /* For sysfs info */
+       struct ep_device                *ep_dev;        /* For sysfs info */
 
        unsigned char *extra;   /* Extra descriptors */
        int extralen;
@@ -101,7 +103,8 @@ enum usb_interface_condition {
  * @condition: binding state of the interface: not bound, binding
  *     (in probe()), bound to a driver, or unbinding (in disconnect())
  * @dev: driver model's view of this device
- * @class_dev: driver model's class view of this device.
+ * @usb_dev: if an interface is bound to the USB major, this will point
+ *     to the sysfs representation for that device.
  *
  * USB device drivers attach to interfaces on a physical device.  Each
  * interface encapsulates a single high level function, such as feeding
@@ -141,7 +144,7 @@ struct usb_interface {
                                         * bound to */
        enum usb_interface_condition condition;         /* state of binding */
        struct device dev;              /* interface specific device info */
-       struct class_device *class_dev;
+       struct device *usb_dev;         /* pointer to the usb class's device, if any */
 };
 #define        to_usb_interface(d) container_of(d, struct usb_interface, dev)
 #define        interface_to_usbdev(intf) \
@@ -358,7 +361,7 @@ struct usb_device {
        char *serial;                   /* iSerialNumber string, if present */
 
        struct list_head filelist;
-       struct class_device *class_dev;
+       struct device *usbfs_dev;
        struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */
 
        /*
@@ -386,6 +389,8 @@ extern int usb_lock_device_for_reset(struct usb_device *udev,
 
 /* USB port reset for device reinitialization */
 extern int usb_reset_device(struct usb_device *dev);
+extern int usb_reset_composite_device(struct usb_device *dev,
+               struct usb_interface *iface);
 
 extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
 
@@ -554,6 +559,10 @@ struct usb_dynids {
  *     do (or don't) show up otherwise in the filesystem.
  * @suspend: Called when the device is going to be suspended by the system.
  * @resume: Called when the device is being resumed by the system.
+ * @pre_reset: Called by usb_reset_composite_device() when the device
+ *     is about to be reset.
+ * @post_reset: Called by usb_reset_composite_device() after the device
+ *     has been reset.
  * @id_table: USB drivers use ID table to support hotplugging.
  *     Export this with MODULE_DEVICE_TABLE(usb,...).  This must be set
  *     or your driver's probe function will never get called.
@@ -592,6 +601,9 @@ struct usb_driver {
        int (*suspend) (struct usb_interface *intf, pm_message_t message);
        int (*resume) (struct usb_interface *intf);
 
+       void (*pre_reset) (struct usb_interface *intf);
+       void (*post_reset) (struct usb_interface *intf);
+
        const struct usb_device_id *id_table;
 
        struct usb_dynids dynids;
@@ -1008,6 +1020,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
 extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
        __u8 request, __u8 requesttype, __u16 value, __u16 index,
        void *data, __u16 size, int timeout);
+extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
+       void *data, int len, int *actual_length, int timeout);
 extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
        void *data, int len, int *actual_length,
        int timeout);
similarity index 71%
rename from include/linux/usb_sl811.h
rename to include/linux/usb/sl811.h
index 4f2d012d7309937e4597d6369bb9b67b54c6a24d..397ee3b3d7f357ff5d2d665491c12a28f478d909 100644 (file)
@@ -14,13 +14,13 @@ struct sl811_platform_data {
        u8              power;
 
        /* sl811 relies on an external source of VBUS current */
-       void            (*port_power)(struct device *dev, int is_on);
+       void            (*port_power)(struct device *dev, int is_on);
 
        /* pulse sl811 nRST (probably with a GPIO) */
-       void            (*reset)(struct device *dev);
+       void            (*reset)(struct device *dev);
 
        // some boards need something like these:
-       // int          (*check_overcurrent)(struct device *dev);
-       // void         (*clock_enable)(struct device *dev, int is_on);
+       // int          (*check_overcurrent)(struct device *dev);
+       // void         (*clock_enable)(struct device *dev, int is_on);
 };
 
index f1cfd66b9554bfe27fcfbd40559222909ff1c542..0beb75e38caa6e93411879047d7c3b1b83b9fc81 100644 (file)
  */
 #ifndef MAX_WBITS
 #  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+
+/* default memLevel */
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
 #endif
 
                         /* Type declarations */
index 4fa32f0d4df8a0ad345dabc793c4105cb4094648..9e3192a7dc6fa7ca7bf6746766234cf9261ed382 100644 (file)
@@ -1,7 +1,6 @@
 /* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.1.3, July 9th, 1998
 
-  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -24,7 +23,7 @@
 
 
   The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
   (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
 */
 
 
 #include <linux/zconf.h>
 
-#define ZLIB_VERSION "1.1.3"
+/* zlib deflate based on ZLIB_VERSION "1.1.3" */
+/* zlib inflate based on ZLIB_VERSION "1.2.3" */
+
+/*
+  This is a modified version of zlib for use inside the Linux kernel.
+  The main changes are to perform all memory allocation in advance.
+
+  Inflation Changes:
+    * Z_PACKET_FLUSH is added and used by ppp_deflate. Before returning
+      this checks there is no more input data available and the next data
+      is a STORED block. It also resets the mode to be read for the next
+      data, all as per PPP requirements.
+    * Addition of zlib_inflateIncomp which copies incompressible data into
+      the history window and adjusts the accoutning without calling
+      zlib_inflate itself to inflate the data.
+*/
 
 /* 
      The 'zlib' compression library provides in-memory compression and
   application must provide more input and/or consume the output
   (providing more output space) before each call.
 
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
      The library also supports reading and writing files in gzip (.gz) format
   with an interface similar to that of stdio.
 
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
      The library does not install any signal handler. The decoder checks
   the consistency of the compressed data, so the library should never
   crash even in case of corrupted input.
@@ -119,7 +142,8 @@ typedef z_stream *z_streamp;
 #define Z_SYNC_FLUSH    3
 #define Z_FULL_FLUSH    4
 #define Z_FINISH        5
-/* Allowed flush values; see deflate() below for details */
+#define Z_BLOCK         6 /* Only for inflate at present */
+/* Allowed flush values; see deflate() and inflate() below for details */
 
 #define Z_OK            0
 #define Z_STREAM_END    1
@@ -155,13 +179,6 @@ typedef z_stream *z_streamp;
 
                         /* basic functions */
 
-extern const char * zlib_zlibVersion (void);
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
 extern int zlib_deflate_workspacesize (void);
 /*
    Returns the number of bytes that needs to be allocated for a per-
@@ -315,9 +332,9 @@ extern int zlib_inflateInit (z_streamp strm);
 extern int zlib_inflate (z_streamp strm, int flush);
 /*
     inflate decompresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may some
-  introduce some output latency (reading input without producing any output)
-  except when forced to flush.
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
 
   The detailed semantics are as follows. inflate performs one or both of the
   following actions:
@@ -341,11 +358,26 @@ extern int zlib_inflate (z_streamp strm, int flush);
   must be called again after making room in the output buffer because there
   might be more output pending.
 
-    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
-  output as possible to the output buffer. The flushing behavior of inflate is
-  not specified for values of the flush parameter other than Z_SYNC_FLUSH
-  and Z_FINISH, but the current implementation actually flushes as much output
-  as possible anyway.
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
 
     inflate() should normally be called until it returns Z_STREAM_END or an
   error. However if all decompression is to be performed in a single step
@@ -355,29 +387,44 @@ extern int zlib_inflate (z_streamp strm, int flush);
   uncompressed data. (The size of the uncompressed data may have been saved
   by the compressor for this purpose.) The next operation on this stream must
   be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster routine
+  is never required, but can be used to inform inflate that a faster approach
   may be used for the single inflate() call.
 
-     If a preset dictionary is needed at this point (see inflateSetDictionary
-  below), inflate sets strm-adler to the adler32 checksum of the
-  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
-  it sets strm->adler to the adler32 checksum of all output produced
-  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
-  an error code as described below. At the end of the stream, inflate()
-  checks that its computed adler32 checksum is equal to that saved by the
-  compressor and returns Z_STREAM_END only if the checksum is correct.
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
 
     inflate() returns Z_OK if some progress has been made (more input processed
   or more output produced), Z_STREAM_END if the end of the compressed data has
   been reached and all uncompressed output has been produced, Z_NEED_DICT if a
   preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
-  corrupted (input stream not conforming to the zlib format or incorrect
-  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
-  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
-  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
-  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
-  case, the application may then call inflateSync to look for a good
-  compression block.
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
 */
 
 
@@ -547,16 +594,36 @@ extern int inflateInit2 (z_streamp strm, int  windowBits);
      The windowBits parameter is the base two logarithm of the maximum window
    size (the size of the history buffer).  It should be in the range 8..15 for
    this version of the library. The default value is 15 if inflateInit is used
-   instead. If a compressed stream with a larger window size is given as
-   input, inflate() will return with the error code Z_DATA_ERROR instead of
-   trying to allocate a larger window.
-
-      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
-   memLevel). msg is set to null if there is no error message.  inflateInit2
-   does not perform any decompression apart from reading the zlib header if
-   present: this will be done by inflate(). (So next_in and avail_in may be
-   modified, but next_out and avail_out are unchanged.)
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
 */
 
 extern int zlib_inflateSetDictionary (z_streamp strm,
@@ -564,16 +631,19 @@ extern int zlib_inflateSetDictionary (z_streamp strm,
                                                     uInt  dictLength);
 /*
      Initializes the decompression dictionary from the given uncompressed byte
-   sequence. This function must be called immediately after a call of inflate
-   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
-   can be determined from the Adler32 value returned by this call of
-   inflate. The compressor and decompressor must use exactly the same
-   dictionary (see deflateSetDictionary).
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
 
      inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
    parameter is invalid (such as NULL dictionary) or the stream state is
    inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   expected one (incorrect adler32 value). inflateSetDictionary does not
    perform any decompression: this will be done by subsequent calls of
    inflate().
 */
@@ -614,40 +684,19 @@ extern int zlib_inflateIncomp (z_stream *strm);
    containing the data at next_in (except that the data is not output).
 */
 
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-extern int zlib_deflateInit_ (z_streamp strm, int level,
-                                     const char *version, int stream_size);
-extern int zlib_inflateInit_ (z_streamp strm,
-                                     const char *version, int stream_size);
-extern int zlib_deflateInit2_ (z_streamp strm, int  level, int  method,
-                                      int windowBits, int memLevel,
-                                      int strategy, const char *version,
-                                      int stream_size);
-extern int zlib_inflateInit2_ (z_streamp strm, int  windowBits,
-                                      const char *version, int stream_size);
 #define zlib_deflateInit(strm, level) \
-        zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+       zlib_deflateInit2((strm), (level), Z_DEFLATED, MAX_WBITS, \
+                             DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY)
 #define zlib_inflateInit(strm) \
-        zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-                      (strategy), ZLIB_VERSION, sizeof(z_stream))
-#define zlib_inflateInit2(strm, windowBits) \
-        zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+       zlib_inflateInit2((strm), DEF_WBITS)
 
+extern int zlib_deflateInit2(z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy);
+extern int zlib_inflateInit2(z_streamp strm, int  windowBits);
 
 #if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
     struct internal_state {int dummy;}; /* hack for buggy compilers */
 #endif
 
-extern const char  * zlib_zError           (int err);
-#if 0
-extern int           zlib_inflateSyncPoint (z_streamp z);
-#endif
-extern const uLong * zlib_get_crc_table    (void);
-
 #endif /* _ZLIB_H */
index ee0c59cf2136d5c3dfc7c812bb76e1866f1c7eec..6adfa9a6ffe963dd89dcf895f65c576d1c7a7c97 100644 (file)
@@ -23,18 +23,6 @@ typedef unsigned long  ulg;
 
         /* common constants */
 
-#ifndef DEF_WBITS
-#  define DEF_WBITS MAX_WBITS
-#endif
-/* default windowBits for decompression. MAX_WBITS is for compression only */
-
-#if MAX_MEM_LEVEL >= 8
-#  define DEF_MEM_LEVEL 8
-#else
-#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#endif
-/* default memLevel */
-
 #define STORED_BLOCK 0
 #define STATIC_TREES 1
 #define DYN_TREES    2
index b45a7371274806f2c058bc7a43cb7c59a3e82124..446afc3ea27fab8b506e7f2c274311ecc0bd6c67 100644 (file)
 #define AC97_HAS_NO_MIC        (1<<15) /* no MIC volume */
 #define AC97_HAS_NO_TONE       (1<<16) /* no Tone volume */
 #define AC97_HAS_NO_STD_PCM    (1<<17) /* no standard AC97 PCM volume and mute */
+#define AC97_HAS_NO_AUX                (1<<18) /* no standard AC97 AUX volume and mute */
 
 /* rates indexes */
 #define AC97_RATES_FRONT_DAC   0
index 6691e4aa4ea7f527ca4e2074a842929b06905ed3..3f2f4042a20dddeec4b11aea909e0a2d4df94e69 100644 (file)
@@ -605,6 +605,10 @@ struct snd_seq_remove_events {
 #define SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11)      /* Sampling device (support sample download) */
 #define SNDRV_SEQ_PORT_TYPE_SAMPLE     (1<<12) /* Sampling device (sample can be downloaded at any time) */
 /*...*/
+#define SNDRV_SEQ_PORT_TYPE_HARDWARE   (1<<16) /* driver for a hardware device */
+#define SNDRV_SEQ_PORT_TYPE_SOFTWARE   (1<<17) /* implemented in software */
+#define SNDRV_SEQ_PORT_TYPE_SYNTHESIZER        (1<<18) /* generates sound */
+#define SNDRV_SEQ_PORT_TYPE_PORT       (1<<19) /* connects to other device(s) */
 #define SNDRV_SEQ_PORT_TYPE_APPLICATION        (1<<20) /* application (sequencer/editor) */
 
 /* misc. conditioning flags */
index 9cc021c7ee118e6a110163ffb35121afb8fa55f5..41885f48ad915d36c2dbed39b8c14a98283a2ba6 100644 (file)
@@ -137,7 +137,7 @@ enum {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 7)
+#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 8)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
index 5135147f20e89db0413eff0c1ee99dea305af0be..5d184be0ff728d5a0ce7b47d525d9594179d23f5 100644 (file)
@@ -233,9 +233,8 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
 
 /* init.c */
 
-extern unsigned int snd_cards_lock;
 extern struct snd_card *snd_cards[SNDRV_CARDS];
-extern rwlock_t snd_card_rwlock;
+int snd_card_locked(int card);
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 #define SND_MIXER_OSS_NOTIFY_REGISTER  0
 #define SND_MIXER_OSS_NOTIFY_DISCONNECT        1
index 186e00ad9e79fe8a92f0bc7eba9c6965ae74440f..884bbf54cd36115610c3604aefb26397ed6f30f2 100644 (file)
 #define A_IOCFG_GPOUT0         0x0044          /* analog/digital                               */
 #define A_IOCFG_DISABLE_ANALOG 0x0040          /* = 'enable' for Audigy2 (chiprev=4)           */
 #define A_IOCFG_ENABLE_DIGITAL 0x0004
+#define A_IOCFG_ENABLE_DIGITAL_AUDIGY4 0x0080
 #define A_IOCFG_UNKNOWN_20      0x0020
 #define A_IOCFG_DISABLE_AC97_FRONT      0x0080  /* turn off ac97 front -> front (10k2.1)       */
 #define A_IOCFG_GPOUT1         0x0002          /* IR? drive's internal bypass (?)              */
@@ -1065,6 +1066,7 @@ struct snd_emu_chip_details {
        unsigned char emu1212m;     /* EMU 1212m card */
        unsigned char spi_dac;      /* SPI interface for DAC */
        unsigned char i2c_adc;      /* I2C interface for ADC */
+       unsigned char adc_1361t;    /* Use Philips 1361T ADC */
        const char *driver;
        const char *name;
        const char *id;         /* for backward compatibility - can be NULL if not needed */
index f23d8381c216a0cfc9b9f5b2e1232c677987534d..74f6996769c7db6d706d77a60be3eabf8cec0d25 100644 (file)
@@ -27,9 +27,9 @@
 /* buffer for information */
 struct snd_info_buffer {
        char *buffer;           /* pointer to begin of buffer */
-       char *curr;             /* current position in buffer */
-       unsigned long size;     /* current size */
-       unsigned long len;      /* total length of buffer */
+       unsigned int curr;      /* current position in buffer */
+       unsigned int size;      /* current size */
+       unsigned int len;       /* total length of buffer */
        int stop;               /* stop flag */
        int error;              /* error code */
 };
@@ -40,8 +40,6 @@ struct snd_info_buffer {
 struct snd_info_entry;
 
 struct snd_info_entry_text {
-       unsigned long read_size;
-       unsigned long write_size;
        void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer);
        void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer);
 };
@@ -132,11 +130,9 @@ int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_e
 
 static inline void snd_info_set_text_ops(struct snd_info_entry *entry, 
                                         void *private_data,
-                                        long read_size,
                                         void (*read)(struct snd_info_entry *, struct snd_info_buffer *))
 {
        entry->private_data = private_data;
-       entry->c.text.read_size = read_size;
        entry->c.text.read = read;
 }
 
@@ -167,7 +163,6 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name,
                                    struct snd_info_entry **entryp) { return -EINVAL; }
 static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)),
                                         void *private_data,
-                                        long read_size,
                                         void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {}
 
 static inline int snd_info_check_reserved_words(const char *str) { return 1; }
index 8e97ace78f1679b2d62501470cd2cf8439a2c8b2..ac504321ea5625775698a3735f9b5bbf252c418f 100644 (file)
 #define MPU401_HW_PC98II               18      /* Roland PC98II */
 #define MPU401_HW_AUREAL               19      /* Aureal Vortex */
 
+#define MPU401_INFO_INPUT      (1 << 0)        /* input stream */
+#define MPU401_INFO_OUTPUT     (1 << 1)        /* output stream */
+#define MPU401_INFO_INTEGRATED (1 << 2)        /* integrated h/w port */
+#define MPU401_INFO_MMIO       (1 << 3)        /* MMIO access */
+#define MPU401_INFO_TX_IRQ     (1 << 4)        /* independent TX irq */
+
 #define MPU401_MODE_BIT_INPUT          0
 #define MPU401_MODE_BIT_OUTPUT         1
 #define MPU401_MODE_BIT_INPUT_TRIGGER  2
@@ -62,6 +68,7 @@ struct snd_mpu401 {
        struct snd_rawmidi *rmidi;
 
        unsigned short hardware;        /* MPU401_HW_XXXX */
+       unsigned int info_flags;        /* MPU401_INFO_XXX */
        unsigned long port;             /* base port of MPU-401 chip */
        unsigned long cport;            /* port + 1 (usually) */
        struct resource *res;           /* port resource */
@@ -99,13 +106,16 @@ struct snd_mpu401 {
 
  */
 
-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
+                                     struct pt_regs *regs);
+irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
+                                        struct pt_regs *regs);
 
 int snd_mpu401_uart_new(struct snd_card *card,
                        int device,
                        unsigned short hardware,
                        unsigned long port,
-                       int integrated,
+                       unsigned int info_flags,
                        int irq,
                        int irq_flags,
                        struct snd_rawmidi ** rrawmidi);
index 373425895faa30bd27db93d8d24e40209bcd4ed4..f84d84993a31e83cf9d603f3f3e88c12db9e0411 100644 (file)
@@ -300,7 +300,6 @@ struct snd_pcm_runtime {
        /* -- mmap -- */
        volatile struct snd_pcm_mmap_status *status;
        volatile struct snd_pcm_mmap_control *control;
-       atomic_t mmap_count;
 
        /* -- locking / scheduling -- */
        wait_queue_head_t sleep;
@@ -368,7 +367,9 @@ struct snd_pcm_substream {
        struct snd_pcm_group *group;            /* pointer to current group */
        /* -- assigned files -- */
        void *file;
-       struct file *ffile;
+       int ref_count;
+       atomic_t mmap_count;
+       unsigned int f_flags;
        void (*pcm_release)(struct snd_pcm_substream *);
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        /* -- OSS things -- */
@@ -387,7 +388,7 @@ struct snd_pcm_substream {
        unsigned int hw_opened: 1;
 };
 
-#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL)
+#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
 
 
 struct snd_pcm_str {
@@ -825,14 +826,6 @@ int snd_interval_ratnum(struct snd_interval *i,
 
 void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
 void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var);
-int snd_pcm_hw_param_near(struct snd_pcm_substream *substream, 
-                         struct snd_pcm_hw_params *params,
-                         snd_pcm_hw_param_t var, 
-                         unsigned int val, int *dir);
-int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
-                        struct snd_pcm_hw_params *params,
-                        snd_pcm_hw_param_t var,
-                        unsigned int val, int dir);
 int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
 
 int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
@@ -979,13 +972,13 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
 static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
 {
        struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
-       atomic_inc(&substream->runtime->mmap_count);
+       atomic_inc(&substream->mmap_count);
 }
 
 static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
 {
        struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
-       atomic_dec(&substream->runtime->mmap_count);
+       atomic_dec(&substream->mmap_count);
 }
 
 /* mmap for io-memory area */
index fb18aef77341aa3361c136f39eabfe74a9456ad5..85cf1cf4f31a7a202e8e5faa91f992f3aa1a90ef 100644 (file)
  *
  */
 
-extern int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, const struct snd_mask *val);
-extern unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
-                                              snd_pcm_hw_param_t var, int *dir);
-extern unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
-                                              snd_pcm_hw_param_t var, int *dir);
-extern int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, unsigned int val, int dir);
-extern int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
-                                       snd_pcm_hw_param_t var);
-extern int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, unsigned int val, int dir);
-
-/* To share the same code we have  alsa-lib */
-#define INLINE static inline
-#define assert(a) (void)(a)
+int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 
+                          struct snd_pcm_hw_params *params,
+                          snd_pcm_hw_param_t var, int *dir);
+int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, 
+                         struct snd_pcm_hw_params *params,
+                         snd_pcm_hw_param_t var, int *dir);
+int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
+                          snd_pcm_hw_param_t var, int *dir);
 
 #define SNDRV_MASK_BITS        64      /* we use so far 64bits only */
 #define SNDRV_MASK_SIZE        (SNDRV_MASK_BITS / 32)
 #define MASK_OFS(i)    ((i) >> 5)
 #define MASK_BIT(i)    (1U << ((i) & 31))
 
-INLINE unsigned int ld2(u_int32_t v)
+static inline unsigned int ld2(u_int32_t v)
 {
         unsigned r = 0;
 
@@ -69,22 +61,22 @@ INLINE unsigned int ld2(u_int32_t v)
         return r;
 }
 
-INLINE size_t snd_mask_sizeof(void)
+static inline size_t snd_mask_sizeof(void)
 {
        return sizeof(struct snd_mask);
 }
 
-INLINE void snd_mask_none(struct snd_mask *mask)
+static inline void snd_mask_none(struct snd_mask *mask)
 {
        memset(mask, 0, sizeof(*mask));
 }
 
-INLINE void snd_mask_any(struct snd_mask *mask)
+static inline void snd_mask_any(struct snd_mask *mask)
 {
        memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t));
 }
 
-INLINE int snd_mask_empty(const struct snd_mask *mask)
+static inline int snd_mask_empty(const struct snd_mask *mask)
 {
        int i;
        for (i = 0; i < SNDRV_MASK_SIZE; i++)
@@ -93,10 +85,9 @@ INLINE int snd_mask_empty(const struct snd_mask *mask)
        return 1;
 }
 
-INLINE unsigned int snd_mask_min(const struct snd_mask *mask)
+static inline unsigned int snd_mask_min(const struct snd_mask *mask)
 {
        int i;
-       assert(!snd_mask_empty(mask));
        for (i = 0; i < SNDRV_MASK_SIZE; i++) {
                if (mask->bits[i])
                        return ffs(mask->bits[i]) - 1 + (i << 5);
@@ -104,10 +95,9 @@ INLINE unsigned int snd_mask_min(const struct snd_mask *mask)
        return 0;
 }
 
-INLINE unsigned int snd_mask_max(const struct snd_mask *mask)
+static inline unsigned int snd_mask_max(const struct snd_mask *mask)
 {
        int i;
-       assert(!snd_mask_empty(mask));
        for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
                if (mask->bits[i])
                        return ld2(mask->bits[i]) + (i << 5);
@@ -115,70 +105,68 @@ INLINE unsigned int snd_mask_max(const struct snd_mask *mask)
        return 0;
 }
 
-INLINE void snd_mask_set(struct snd_mask *mask, unsigned int val)
+static inline void snd_mask_set(struct snd_mask *mask, unsigned int val)
 {
-       assert(val <= SNDRV_MASK_BITS);
        mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
 }
 
-INLINE void snd_mask_reset(struct snd_mask *mask, unsigned int val)
+static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val)
 {
-       assert(val <= SNDRV_MASK_BITS);
        mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
 }
 
-INLINE void snd_mask_set_range(struct snd_mask *mask, unsigned int from, unsigned int to)
+static inline void snd_mask_set_range(struct snd_mask *mask,
+                                     unsigned int from, unsigned int to)
 {
        unsigned int i;
-       assert(to <= SNDRV_MASK_BITS && from <= to);
        for (i = from; i <= to; i++)
                mask->bits[MASK_OFS(i)] |= MASK_BIT(i);
 }
 
-INLINE void snd_mask_reset_range(struct snd_mask *mask, unsigned int from, unsigned int to)
+static inline void snd_mask_reset_range(struct snd_mask *mask,
+                                       unsigned int from, unsigned int to)
 {
        unsigned int i;
-       assert(to <= SNDRV_MASK_BITS && from <= to);
        for (i = from; i <= to; i++)
                mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
 }
 
-INLINE void snd_mask_leave(struct snd_mask *mask, unsigned int val)
+static inline void snd_mask_leave(struct snd_mask *mask, unsigned int val)
 {
        unsigned int v;
-       assert(val <= SNDRV_MASK_BITS);
        v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
        snd_mask_none(mask);
        mask->bits[MASK_OFS(val)] = v;
 }
 
-INLINE void snd_mask_intersect(struct snd_mask *mask, const struct snd_mask *v)
+static inline void snd_mask_intersect(struct snd_mask *mask,
+                                     const struct snd_mask *v)
 {
        int i;
        for (i = 0; i < SNDRV_MASK_SIZE; i++)
                mask->bits[i] &= v->bits[i];
 }
 
-INLINE int snd_mask_eq(const struct snd_mask *mask, const struct snd_mask *v)
+static inline int snd_mask_eq(const struct snd_mask *mask,
+                             const struct snd_mask *v)
 {
        return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t));
 }
 
-INLINE void snd_mask_copy(struct snd_mask *mask, const struct snd_mask *v)
+static inline void snd_mask_copy(struct snd_mask *mask,
+                                const struct snd_mask *v)
 {
        *mask = *v;
 }
 
-INLINE int snd_mask_test(const struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val)
 {
-       assert(val <= SNDRV_MASK_BITS);
        return mask->bits[MASK_OFS(val)] & MASK_BIT(val);
 }
 
-INLINE int snd_mask_single(const struct snd_mask *mask)
+static inline int snd_mask_single(const struct snd_mask *mask)
 {
        int i, c = 0;
-       assert(!snd_mask_empty(mask));
        for (i = 0; i < SNDRV_MASK_SIZE; i++) {
                if (! mask->bits[i])
                        continue;
@@ -191,10 +179,10 @@ INLINE int snd_mask_single(const struct snd_mask *mask)
        return 1;
 }
 
-INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v)
+static inline int snd_mask_refine(struct snd_mask *mask,
+                                 const struct snd_mask *v)
 {
        struct snd_mask old;
-       assert(!snd_mask_empty(mask));
        snd_mask_copy(&old, mask);
        snd_mask_intersect(mask, v);
        if (snd_mask_empty(mask))
@@ -202,27 +190,24 @@ INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v)
        return !snd_mask_eq(mask, &old);
 }
 
-INLINE int snd_mask_refine_first(struct snd_mask *mask)
+static inline int snd_mask_refine_first(struct snd_mask *mask)
 {
-       assert(!snd_mask_empty(mask));
        if (snd_mask_single(mask))
                return 0;
        snd_mask_leave(mask, snd_mask_min(mask));
        return 1;
 }
 
-INLINE int snd_mask_refine_last(struct snd_mask *mask)
+static inline int snd_mask_refine_last(struct snd_mask *mask)
 {
-       assert(!snd_mask_empty(mask));
        if (snd_mask_single(mask))
                return 0;
        snd_mask_leave(mask, snd_mask_max(mask));
        return 1;
 }
 
-INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
 {
-       assert(!snd_mask_empty(mask));
        if (snd_mask_min(mask) >= val)
                return 0;
        snd_mask_reset_range(mask, 0, val - 1);
@@ -231,9 +216,8 @@ INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
        return 1;
 }
 
-INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
 {
-       assert(!snd_mask_empty(mask));
        if (snd_mask_max(mask) <= val)
                return 0;
        snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS);
@@ -242,10 +226,9 @@ INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
        return 1;
 }
 
-INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
+static inline int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
 {
        int changed;
-       assert(!snd_mask_empty(mask));
        changed = !snd_mask_single(mask);
        snd_mask_leave(mask, val);
        if (snd_mask_empty(mask))
@@ -253,13 +236,12 @@ INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
        return changed;
 }
 
-INLINE int snd_mask_value(const struct snd_mask *mask)
+static inline int snd_mask_value(const struct snd_mask *mask)
 {
-       assert(!snd_mask_empty(mask));
        return snd_mask_min(mask);
 }
 
-INLINE void snd_interval_any(struct snd_interval *i)
+static inline void snd_interval_any(struct snd_interval *i)
 {
        i->min = 0;
        i->openmin = 0;
@@ -269,63 +251,59 @@ INLINE void snd_interval_any(struct snd_interval *i)
        i->empty = 0;
 }
 
-INLINE void snd_interval_none(struct snd_interval *i)
+static inline void snd_interval_none(struct snd_interval *i)
 {
        i->empty = 1;
 }
 
-INLINE int snd_interval_checkempty(const struct snd_interval *i)
+static inline int snd_interval_checkempty(const struct snd_interval *i)
 {
        return (i->min > i->max ||
                (i->min == i->max && (i->openmin || i->openmax)));
 }
 
-INLINE int snd_interval_empty(const struct snd_interval *i)
+static inline int snd_interval_empty(const struct snd_interval *i)
 {
        return i->empty;
 }
 
-INLINE int snd_interval_single(const struct snd_interval *i)
+static inline int snd_interval_single(const struct snd_interval *i)
 {
-       assert(!snd_interval_empty(i));
        return (i->min == i->max || 
                (i->min + 1 == i->max && i->openmax));
 }
 
-INLINE int snd_interval_value(const struct snd_interval *i)
+static inline int snd_interval_value(const struct snd_interval *i)
 {
-       assert(snd_interval_single(i));
        return i->min;
 }
 
-INLINE int snd_interval_min(const struct snd_interval *i)
+static inline int snd_interval_min(const struct snd_interval *i)
 {
-       assert(!snd_interval_empty(i));
        return i->min;
 }
 
-INLINE int snd_interval_max(const struct snd_interval *i)
+static inline int snd_interval_max(const struct snd_interval *i)
 {
        unsigned int v;
-       assert(!snd_interval_empty(i));
        v = i->max;
        if (i->openmax)
                v--;
        return v;
 }
 
-INLINE int snd_interval_test(const struct snd_interval *i, unsigned int val)
+static inline int snd_interval_test(const struct snd_interval *i, unsigned int val)
 {
        return !((i->min > val || (i->min == val && i->openmin) ||
                  i->max < val || (i->max == val && i->openmax)));
 }
 
-INLINE void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s)
+static inline void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s)
 {
        *d = *s;
 }
 
-INLINE int snd_interval_setinteger(struct snd_interval *i)
+static inline int snd_interval_setinteger(struct snd_interval *i)
 {
        if (i->integer)
                return 0;
@@ -335,7 +313,7 @@ INLINE int snd_interval_setinteger(struct snd_interval *i)
        return 1;
 }
 
-INLINE int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2)
+static inline int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2)
 {
        if (i1->empty)
                return i2->empty;
@@ -359,8 +337,5 @@ static inline unsigned int sub(unsigned int a, unsigned int b)
        return 0;
 }
 
-#undef INLINE
-#undef assert
-
 #endif /* __SOUND_PCM_PARAMS_H */
 
index 584e73dd479319ea5034282ab107aa9d36e4a621..7dbcd10fa215d00f4f53ea37e8838046fc4b0831 100644 (file)
@@ -46,6 +46,7 @@
 
 struct snd_rawmidi;
 struct snd_rawmidi_substream;
+struct snd_seq_port_info;
 
 struct snd_rawmidi_ops {
        int (*open) (struct snd_rawmidi_substream * substream);
@@ -57,6 +58,8 @@ struct snd_rawmidi_ops {
 struct snd_rawmidi_global_ops {
        int (*dev_register) (struct snd_rawmidi * rmidi);
        int (*dev_unregister) (struct snd_rawmidi * rmidi);
+       void (*get_port_info)(struct snd_rawmidi *rmidi, int number,
+                             struct snd_seq_port_info *info);
 };
 
 struct snd_rawmidi_runtime {
index 4f0e65808cf1a29e39757244ce15509b756e39b0..2ee849d0e198dc20c4afb1b5e26d203272de2e20 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.11rc4"
-#define CONFIG_SND_DATE " (Wed Mar 22 10:27:24 2006 UTC)"
+#define CONFIG_SND_VERSION "1.0.12rc1"
+#define CONFIG_SND_DATE " (Thu Jun 22 13:55:50 2006 UTC)"
index 0a907f0dc56b3bc0f67e189ded38f64e8ad94ebb..cdf0f07af92f91dc58b1a441dcb66ff035b77db4 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/pm.h>
-
+#include <linux/console.h>
 
 #include "power.h"
 
index 0b6ec0e7936f02ebb92477dd12951169a2bc7218..fc9ebbbaba0c4f16d4eceb34269e7b782988a125 100644 (file)
@@ -1860,23 +1860,20 @@ out:
  * fields when reaping, so a sample either gets all the additions of a
  * given child after it's reaped, or none so this sample is before reaping.
  *
- * tasklist_lock locking optimisation:
- * If we are current and single threaded, we do not need to take the tasklist
- * lock or the siglock.  No one else can take our signal_struct away,
- * no one else can reap the children to update signal->c* counters, and
- * no one else can race with the signal-> fields.
- * If we do not take the tasklist_lock, the signal-> fields could be read
- * out of order while another thread was just exiting. So we place a
- * read memory barrier when we avoid the lock.  On the writer side,
- * write memory barrier is implied in  __exit_signal as __exit_signal releases
- * the siglock spinlock after updating the signal-> fields.
- *
- * We don't really need the siglock when we access the non c* fields
- * of the signal_struct (for RUSAGE_SELF) even in multithreaded
- * case, since we take the tasklist lock for read and the non c* signal->
- * fields are updated only in __exit_signal, which is called with
- * tasklist_lock taken for write, hence these two threads cannot execute
- * concurrently.
+ * Locking:
+ * We need to take the siglock for CHILDEREN, SELF and BOTH
+ * for  the cases current multithreaded, non-current single threaded
+ * non-current multithreaded.  Thread traversal is now safe with
+ * the siglock held.
+ * Strictly speaking, we donot need to take the siglock if we are current and
+ * single threaded,  as no one else can take our signal_struct away, no one
+ * else can  reap the  children to update signal->c* counters, and no one else
+ * can race with the signal-> fields. If we do not take any lock, the
+ * signal-> fields could be read out of order while another thread was just
+ * exiting. So we should  place a read memory barrier when we avoid the lock.
+ * On the writer side,  write memory barrier is implied in  __exit_signal
+ * as __exit_signal releases  the siglock spinlock after updating the signal->
+ * fields. But we don't do this yet to keep things simple.
  *
  */
 
@@ -1885,35 +1882,25 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
        struct task_struct *t;
        unsigned long flags;
        cputime_t utime, stime;
-       int need_lock = 0;
 
        memset((char *) r, 0, sizeof *r);
        utime = stime = cputime_zero;
 
-       if (p != current || !thread_group_empty(p))
-               need_lock = 1;
-
-       if (need_lock) {
-               read_lock(&tasklist_lock);
-               if (unlikely(!p->signal)) {
-                       read_unlock(&tasklist_lock);
-                       return;
-               }
-       } else
-               /* See locking comments above */
-               smp_rmb();
+       rcu_read_lock();
+       if (!lock_task_sighand(p, &flags)) {
+               rcu_read_unlock();
+               return;
+       }
 
        switch (who) {
                case RUSAGE_BOTH:
                case RUSAGE_CHILDREN:
-                       spin_lock_irqsave(&p->sighand->siglock, flags);
                        utime = p->signal->cutime;
                        stime = p->signal->cstime;
                        r->ru_nvcsw = p->signal->cnvcsw;
                        r->ru_nivcsw = p->signal->cnivcsw;
                        r->ru_minflt = p->signal->cmin_flt;
                        r->ru_majflt = p->signal->cmaj_flt;
-                       spin_unlock_irqrestore(&p->sighand->siglock, flags);
 
                        if (who == RUSAGE_CHILDREN)
                                break;
@@ -1941,8 +1928,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                        BUG();
        }
 
-       if (need_lock)
-               read_unlock(&tasklist_lock);
+       unlock_task_sighand(p, &flags);
+       rcu_read_unlock();
+
        cputime_to_timeval(utime, &r->ru_utime);
        cputime_to_timeval(stime, &r->ru_stime);
 }
index 4b1eb745afa1031fbf0ec9ef84955ef8e201d664..6408c04242914191405dfef6a21b73948ef5ae73 100644 (file)
@@ -148,7 +148,7 @@ struct user_struct * alloc_uid(uid_t uid)
                new->mq_bytes = 0;
                new->locked_shm = 0;
 
-               if (alloc_uid_keyring(new) < 0) {
+               if (alloc_uid_keyring(new, current) < 0) {
                        kmem_cache_free(uid_cachep, new);
                        return NULL;
                }
index 687ab418d292b15084d8a97be48f6003b0d0e315..8e7c7199348749e63bb4cf17868e2123aa2c44fc 100644 (file)
@@ -198,14 +198,14 @@ int kobject_add(struct kobject * kobj)
 
                /* be noisy on error issues */
                if (error == -EEXIST)
-                       pr_debug("kobject_add failed for %s with -EEXIST, "
+                       printk("kobject_add failed for %s with -EEXIST, "
                               "don't try to register things with the "
                               "same name in the same directory.\n",
                               kobject_name(kobj));
                else
-                       pr_debug("kobject_add failed for %s (%d)\n",
+                       printk("kobject_add failed for %s (%d)\n",
                               kobject_name(kobj), error);
-               /* dump_stack(); */
+                dump_stack();
        }
 
        return error;
index 1653dd9bb01a459aa6105e44b678928c52327c47..c3e4a2baf835abe630929b6138de0a9130a08110 100644 (file)
@@ -164,34 +164,17 @@ static const config configuration_table[10] = {
     memset((char *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head));
 
 /* ========================================================================= */
-int zlib_deflateInit_(
-       z_streamp strm,
-       int level,
-       const char *version,
-       int stream_size
-)
-{
-    return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
-                             DEF_MEM_LEVEL,
-                             Z_DEFAULT_STRATEGY, version, stream_size);
-    /* To do: ignore strm->next_in if we use it as window */
-}
-
-/* ========================================================================= */
-int zlib_deflateInit2_(
+int zlib_deflateInit2(
        z_streamp strm,
        int  level,
        int  method,
        int  windowBits,
        int  memLevel,
-       int  strategy,
-       const char *version,
-       int stream_size
+       int  strategy
 )
 {
     deflate_state *s;
     int noheader = 0;
-    static char* my_version = ZLIB_VERSION;
     deflate_workspace *mem;
 
     ush *overlay;
@@ -199,10 +182,6 @@ int zlib_deflateInit2_(
      * output size for (length,distance) codes is <= 24 bits.
      */
 
-    if (version == NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-       return Z_VERSION_ERROR;
-    }
     if (strm == NULL) return Z_STREAM_ERROR;
 
     strm->msg = NULL;
index 767b573d1ef66a931ff62eecd19cb9c91abb06c2..ccfe25f3920f5922ddcfb03ae325cd3cc7cc74a9 100644 (file)
@@ -12,8 +12,7 @@
 
 EXPORT_SYMBOL(zlib_deflate_workspacesize);
 EXPORT_SYMBOL(zlib_deflate);
-EXPORT_SYMBOL(zlib_deflateInit_);
-EXPORT_SYMBOL(zlib_deflateInit2_);
+EXPORT_SYMBOL(zlib_deflateInit2);
 EXPORT_SYMBOL(zlib_deflateEnd);
 EXPORT_SYMBOL(zlib_deflateReset);
 MODULE_LICENSE("GPL");
index 221c139e0df1d253cd210726b962bfa94812b497..bf065482fa6791a873eb08bbffbdb7eb870ff223 100644 (file)
@@ -15,5 +15,5 @@
 
 obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o
 
-zlib_inflate-objs := infblock.o infcodes.o inffast.o inflate.o \
-                    inflate_sync.o inftrees.o infutil.o inflate_syms.o
+zlib_inflate-objs := inffast.o inflate.o \
+                    inftrees.o inflate_syms.o
diff --git a/lib/zlib_inflate/infblock.c b/lib/zlib_inflate/infblock.c
deleted file mode 100644 (file)
index c16cdef..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/* infblock.c -- interpret and process block types to last block
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include <linux/zutil.h>
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* Table for deflate from PKZIP's appnote.txt. */
-static const uInt border[] = { /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/*
-   Notes beyond the 1.93a appnote.txt:
-
-   1. Distance pointers never point before the beginning of the output
-      stream.
-   2. Distance pointers can point back across blocks, up to 32k away.
-   3. There is an implied maximum of 7 bits for the bit length table and
-      15 bits for the actual data.
-   4. If only one code exists, then it is encoded using one bit.  (Zero
-      would be more efficient, but perhaps a little confusing.)  If two
-      codes exist, they are coded using one bit each (0 and 1).
-   5. There is no way of sending zero distance codes--a dummy must be
-      sent if there are none.  (History: a pre 2.0 version of PKZIP would
-      store blocks with no distance codes, but this was discovered to be
-      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
-      zero distance codes, which is sent as one code of zero bits in
-      length.
-   6. There are up to 286 literal/length codes.  Code 256 represents the
-      end-of-block.  Note however that the static length tree defines
-      288 codes just to fill out the Huffman codes.  Codes 286 and 287
-      cannot be used though, since there is no length base or extra bits
-      defined for them.  Similarily, there are up to 30 distance codes.
-      However, static trees define 32 codes (all 5 bits) to fill out the
-      Huffman codes, but the last two had better not show up in the data.
-   7. Unzip can check dynamic Huffman blocks for complete code sets.
-      The exception is that a single code would not be complete (see #4).
-   8. The five bits following the block type is really the number of
-      literal codes sent minus 257.
-   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
-      (1+6+6).  Therefore, to output three times the length, you output
-      three codes (1+1+1), whereas to output four times the same length,
-      you only need two codes (1+3).  Hmm.
-  10. In the tree reconstruction algorithm, Code = Code + Increment
-      only if BitLength(i) is not zero.  (Pretty obvious.)
-  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
-  12. Note: length code 284 can represent 227-258, but length code 285
-      really is 258.  The last length deserves its own, short code
-      since it gets used a lot in very redundant files.  The length
-      258 is special since 258 - 3 (the min match length) is 255.
-  13. The literal/length and distance code bit lengths are read as a
-      single stream of lengths.  It is possible (and advantageous) for
-      a repeat code (16, 17, or 18) to go across the boundary between
-      the two sets of lengths.
- */
-
-
-void zlib_inflate_blocks_reset(
-       inflate_blocks_statef *s,
-       z_streamp z,
-       uLong *c
-)
-{
-  if (c != NULL)
-    *c = s->check;
-  if (s->mode == CODES)
-    zlib_inflate_codes_free(s->sub.decode.codes, z);
-  s->mode = TYPE;
-  s->bitk = 0;
-  s->bitb = 0;
-  s->read = s->write = s->window;
-  if (s->checkfn != NULL)
-    z->adler = s->check = (*s->checkfn)(0L, NULL, 0);
-}
-
-inflate_blocks_statef *zlib_inflate_blocks_new(
-       z_streamp z,
-       check_func c,
-       uInt w
-)
-{
-  inflate_blocks_statef *s;
-
-  s = &WS(z)->working_blocks_state;
-  s->hufts = WS(z)->working_hufts;
-  s->window = WS(z)->working_window;
-  s->end = s->window + w;
-  s->checkfn = c;
-  s->mode = TYPE;
-  zlib_inflate_blocks_reset(s, z, NULL);
-  return s;
-}
-
-
-int zlib_inflate_blocks(
-       inflate_blocks_statef *s,
-       z_streamp z,
-       int r
-)
-{
-  uInt t;               /* temporary storage */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Byte *p;              /* input data pointer */
-  uInt n;               /* bytes available there */
-  Byte *q;              /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input based on current state */
-  while (1) switch (s->mode)
-  {
-    case TYPE:
-      NEEDBITS(3)
-      t = (uInt)b & 7;
-      s->last = t & 1;
-      switch (t >> 1)
-      {
-        case 0:                         /* stored */
-          DUMPBITS(3)
-          t = k & 7;                    /* go to byte boundary */
-          DUMPBITS(t)
-          s->mode = LENS;               /* get length of stored block */
-          break;
-        case 1:                         /* fixed */
-          {
-            uInt bl, bd;
-            inflate_huft *tl, *td;
-
-            zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, s->hufts, z);
-            s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z);
-            if (s->sub.decode.codes == NULL)
-            {
-              r = Z_MEM_ERROR;
-              LEAVE
-            }
-          }
-          DUMPBITS(3)
-          s->mode = CODES;
-          break;
-        case 2:                         /* dynamic */
-          DUMPBITS(3)
-          s->mode = TABLE;
-          break;
-        case 3:                         /* illegal */
-          DUMPBITS(3)
-          s->mode = B_BAD;
-          z->msg = (char*)"invalid block type";
-          r = Z_DATA_ERROR;
-          LEAVE
-      }
-      break;
-    case LENS:
-      NEEDBITS(32)
-      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
-      {
-        s->mode = B_BAD;
-        z->msg = (char*)"invalid stored block lengths";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-      s->sub.left = (uInt)b & 0xffff;
-      b = k = 0;                      /* dump bits */
-      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
-      break;
-    case STORED:
-      if (n == 0)
-        LEAVE
-      NEEDOUT
-      t = s->sub.left;
-      if (t > n) t = n;
-      if (t > m) t = m;
-      memcpy(q, p, t);
-      p += t;  n -= t;
-      q += t;  m -= t;
-      if ((s->sub.left -= t) != 0)
-        break;
-      s->mode = s->last ? DRY : TYPE;
-      break;
-    case TABLE:
-      NEEDBITS(14)
-      s->sub.trees.table = t = (uInt)b & 0x3fff;
-#ifndef PKZIP_BUG_WORKAROUND
-      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
-      {
-        s->mode = B_BAD;
-        z->msg = (char*)"too many length or distance symbols";
-        r = Z_DATA_ERROR;
-        LEAVE
-      }
-#endif
-      {
-       s->sub.trees.blens = WS(z)->working_blens;
-      }
-      DUMPBITS(14)
-      s->sub.trees.index = 0;
-      s->mode = BTREE;
-    case BTREE:
-      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
-      {
-        NEEDBITS(3)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
-        DUMPBITS(3)
-      }
-      while (s->sub.trees.index < 19)
-        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
-      s->sub.trees.bb = 7;
-      t = zlib_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
-                                 &s->sub.trees.tb, s->hufts, z);
-      if (t != Z_OK)
-      {
-        r = t;
-        if (r == Z_DATA_ERROR)
-          s->mode = B_BAD;
-        LEAVE
-      }
-      s->sub.trees.index = 0;
-      s->mode = DTREE;
-    case DTREE:
-      while (t = s->sub.trees.table,
-             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
-      {
-        inflate_huft *h;
-        uInt i, j, c;
-
-        t = s->sub.trees.bb;
-        NEEDBITS(t)
-        h = s->sub.trees.tb + ((uInt)b & zlib_inflate_mask[t]);
-        t = h->bits;
-        c = h->base;
-        if (c < 16)
-        {
-          DUMPBITS(t)
-          s->sub.trees.blens[s->sub.trees.index++] = c;
-        }
-        else /* c == 16..18 */
-        {
-          i = c == 18 ? 7 : c - 14;
-          j = c == 18 ? 11 : 3;
-          NEEDBITS(t + i)
-          DUMPBITS(t)
-          j += (uInt)b & zlib_inflate_mask[i];
-          DUMPBITS(i)
-          i = s->sub.trees.index;
-          t = s->sub.trees.table;
-          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
-              (c == 16 && i < 1))
-          {
-            s->mode = B_BAD;
-            z->msg = (char*)"invalid bit length repeat";
-            r = Z_DATA_ERROR;
-            LEAVE
-          }
-          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
-          do {
-            s->sub.trees.blens[i++] = c;
-          } while (--j);
-          s->sub.trees.index = i;
-        }
-      }
-      s->sub.trees.tb = NULL;
-      {
-        uInt bl, bd;
-        inflate_huft *tl, *td;
-        inflate_codes_statef *c;
-
-        bl = 9;         /* must be <= 9 for lookahead assumptions */
-        bd = 6;         /* must be <= 9 for lookahead assumptions */
-        t = s->sub.trees.table;
-        t = zlib_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
-                                      s->sub.trees.blens, &bl, &bd, &tl, &td,
-                                      s->hufts, z);
-        if (t != Z_OK)
-        {
-          if (t == (uInt)Z_DATA_ERROR)
-            s->mode = B_BAD;
-          r = t;
-          LEAVE
-        }
-        if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == NULL)
-        {
-          r = Z_MEM_ERROR;
-          LEAVE
-        }
-        s->sub.decode.codes = c;
-      }
-      s->mode = CODES;
-    case CODES:
-      UPDATE
-      if ((r = zlib_inflate_codes(s, z, r)) != Z_STREAM_END)
-        return zlib_inflate_flush(s, z, r);
-      r = Z_OK;
-      zlib_inflate_codes_free(s->sub.decode.codes, z);
-      LOAD
-      if (!s->last)
-      {
-        s->mode = TYPE;
-        break;
-      }
-      s->mode = DRY;
-    case DRY:
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      s->mode = B_DONE;
-    case B_DONE:
-      r = Z_STREAM_END;
-      LEAVE
-    case B_BAD:
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-}
-
-
-int zlib_inflate_blocks_free(
-       inflate_blocks_statef *s,
-       z_streamp z
-)
-{
-  zlib_inflate_blocks_reset(s, z, NULL);
-  return Z_OK;
-}
-
-
-#if 0
-void zlib_inflate_set_dictionary(
-       inflate_blocks_statef *s,
-       const Byte *d,
-       uInt  n
-)
-{
-  memcpy(s->window, d, n);
-  s->read = s->write = s->window + n;
-}
-#endif  /*  0  */
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
- * IN assertion: s != NULL
- */
-#if 0
-int zlib_inflate_blocks_sync_point(
-       inflate_blocks_statef *s
-)
-{
-  return s->mode == LENS;
-}
-#endif  /*  0  */
diff --git a/lib/zlib_inflate/infblock.h b/lib/zlib_inflate/infblock.h
deleted file mode 100644 (file)
index ceee60b..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* infblock.h -- header to use infblock.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFBLOCK_H
-#define _INFBLOCK_H
-
-struct inflate_blocks_state;
-typedef struct inflate_blocks_state inflate_blocks_statef;
-
-extern inflate_blocks_statef * zlib_inflate_blocks_new (
-    z_streamp z,
-    check_func c,              /* check function */
-    uInt w);                   /* window size */
-
-extern int zlib_inflate_blocks (
-    inflate_blocks_statef *,
-    z_streamp ,
-    int);                      /* initial return code */
-
-extern void zlib_inflate_blocks_reset (
-    inflate_blocks_statef *,
-    z_streamp ,
-    uLong *);                  /* check value on output */
-
-extern int zlib_inflate_blocks_free (
-    inflate_blocks_statef *,
-    z_streamp);
-
-#if 0
-extern void zlib_inflate_set_dictionary (
-    inflate_blocks_statef *s,
-    const Byte *d,  /* dictionary */
-    uInt  n);       /* dictionary length */
-#endif  /*  0  */
-
-#if 0
-extern int zlib_inflate_blocks_sync_point (
-    inflate_blocks_statef *s);
-#endif  /*  0  */
-
-#endif /* _INFBLOCK_H */
diff --git a/lib/zlib_inflate/infcodes.c b/lib/zlib_inflate/infcodes.c
deleted file mode 100644 (file)
index 07cd759..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/* infcodes.c -- process literals and length/distance pairs
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include <linux/zutil.h>
-#include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
-#include "inffast.h"
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-inflate_codes_statef *zlib_inflate_codes_new(
-       uInt bl,
-       uInt bd,
-       inflate_huft *tl,
-       inflate_huft *td, /* need separate declaration for Borland C++ */
-       z_streamp z
-)
-{
-  inflate_codes_statef *c;
-
-  c = &WS(z)->working_state;
-  {
-    c->mode = START;
-    c->lbits = (Byte)bl;
-    c->dbits = (Byte)bd;
-    c->ltree = tl;
-    c->dtree = td;
-  }
-  return c;
-}
-
-
-int zlib_inflate_codes(
-       inflate_blocks_statef *s,
-       z_streamp z,
-       int r
-)
-{
-  uInt j;               /* temporary storage */
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Byte *p;              /* input data pointer */
-  uInt n;               /* bytes available there */
-  Byte *q;              /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  Byte *f;              /* pointer to copy strings from */
-  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
-
-  /* copy input/output information to locals (UPDATE macro restores) */
-  LOAD
-
-  /* process input and output based on current state */
-  while (1) switch (c->mode)
-  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-    case START:         /* x: set up for LEN */
-#ifndef SLOW
-      if (m >= 258 && n >= 10)
-      {
-        UPDATE
-        r = zlib_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
-        LOAD
-        if (r != Z_OK)
-        {
-          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
-          break;
-        }
-      }
-#endif /* !SLOW */
-      c->sub.code.need = c->lbits;
-      c->sub.code.tree = c->ltree;
-      c->mode = LEN;
-    case LEN:           /* i: get length/literal/eob next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e == 0)               /* literal */
-      {
-        c->sub.lit = t->base;
-        c->mode = LIT;
-        break;
-      }
-      if (e & 16)               /* length */
-      {
-        c->sub.copy.get = e & 15;
-        c->len = t->base;
-        c->mode = LENEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t + t->base;
-        break;
-      }
-      if (e & 32)               /* end of block */
-      {
-        c->mode = WASH;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid literal/length code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case LENEXT:        /* i: getting length extra (have base) */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->len += (uInt)b & zlib_inflate_mask[j];
-      DUMPBITS(j)
-      c->sub.code.need = c->dbits;
-      c->sub.code.tree = c->dtree;
-      c->mode = DIST;
-    case DIST:          /* i: get distance next */
-      j = c->sub.code.need;
-      NEEDBITS(j)
-      t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]);
-      DUMPBITS(t->bits)
-      e = (uInt)(t->exop);
-      if (e & 16)               /* distance */
-      {
-        c->sub.copy.get = e & 15;
-        c->sub.copy.dist = t->base;
-        c->mode = DISTEXT;
-        break;
-      }
-      if ((e & 64) == 0)        /* next table */
-      {
-        c->sub.code.need = e;
-        c->sub.code.tree = t + t->base;
-        break;
-      }
-      c->mode = BADCODE;        /* invalid code */
-      z->msg = (char*)"invalid distance code";
-      r = Z_DATA_ERROR;
-      LEAVE
-    case DISTEXT:       /* i: getting distance extra */
-      j = c->sub.copy.get;
-      NEEDBITS(j)
-      c->sub.copy.dist += (uInt)b & zlib_inflate_mask[j];
-      DUMPBITS(j)
-      c->mode = COPY;
-    case COPY:          /* o: copying bytes in window, waiting for space */
-      f = q - c->sub.copy.dist;
-      while (f < s->window)             /* modulo window size-"while" instead */
-        f += s->end - s->window;        /* of "if" handles invalid distances */
-      while (c->len)
-      {
-        NEEDOUT
-        OUTBYTE(*f++)
-        if (f == s->end)
-          f = s->window;
-        c->len--;
-      }
-      c->mode = START;
-      break;
-    case LIT:           /* o: got literal, waiting for output space */
-      NEEDOUT
-      OUTBYTE(c->sub.lit)
-      c->mode = START;
-      break;
-    case WASH:          /* o: got eob, possibly more output */
-      if (k > 7)        /* return unused byte, if any */
-      {
-        k -= 8;
-        n++;
-        p--;            /* can always return one */
-      }
-      FLUSH
-      if (s->read != s->write)
-        LEAVE
-      c->mode = END;
-    case END:
-      r = Z_STREAM_END;
-      LEAVE
-    case BADCODE:       /* x: got error */
-      r = Z_DATA_ERROR;
-      LEAVE
-    default:
-      r = Z_STREAM_ERROR;
-      LEAVE
-  }
-#ifdef NEED_DUMMY_RETURN
-  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
-#endif
-}
-
-
-void zlib_inflate_codes_free(
-       inflate_codes_statef *c,
-       z_streamp z
-)
-{
-}
diff --git a/lib/zlib_inflate/infcodes.h b/lib/zlib_inflate/infcodes.h
deleted file mode 100644 (file)
index 5cff417..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* infcodes.h -- header to use infcodes.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-/* WARNING: this file should *not* be used by applications. It is
-   part of the implementation of the compression library and is
-   subject to change. Applications should only use zlib.h.
- */
-
-#ifndef _INFCODES_H
-#define _INFCODES_H
-
-#include "infblock.h"
-
-struct inflate_codes_state;
-typedef struct inflate_codes_state inflate_codes_statef;
-
-extern inflate_codes_statef *zlib_inflate_codes_new (
-    uInt, uInt,
-    inflate_huft *, inflate_huft *,
-    z_streamp );
-
-extern int zlib_inflate_codes (
-    inflate_blocks_statef *,
-    z_streamp ,
-    int);
-
-extern void zlib_inflate_codes_free (
-    inflate_codes_statef *,
-    z_streamp );
-
-#endif /* _INFCODES_H */
index 0bd7623fc85acefb2698cfc447ff2f6ca986a280..02a16eacb72dabb50861193db448004b175bd3dc 100644 (file)
-/* inffast.c -- process literals and length/distance pairs fast
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
 #include <linux/zutil.h>
 #include "inftrees.h"
-#include "infblock.h"
-#include "infcodes.h"
-#include "infutil.h"
+#include "inflate.h"
 #include "inffast.h"
 
-struct inflate_codes_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-/* macros for bit input with no checking and for returning unused bytes */
-#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
-
-/* Called with number of bytes left to write in window at least 258
-   (the maximum string length) and number of input bytes available
-   at least ten.  The ten bytes are six bytes for the longest length/
-   distance pair plus four bytes for overloading the bit buffer. */
-
-int zlib_inflate_fast(
-       uInt bl,
-       uInt bd,
-       inflate_huft *tl,
-       inflate_huft *td, /* need separate declaration for Borland C++ */
-       inflate_blocks_statef *s,
-       z_streamp z
-)
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
 {
-  inflate_huft *t;      /* temporary pointer */
-  uInt e;               /* extra bits or operation */
-  uLong b;              /* bit buffer */
-  uInt k;               /* bits in bit buffer */
-  Byte *p;              /* input data pointer */
-  uInt n;               /* bytes available there */
-  Byte *q;              /* output window write pointer */
-  uInt m;               /* bytes to end of window or read pointer */
-  uInt ml;              /* mask for literal/length tree */
-  uInt md;              /* mask for distance tree */
-  uInt c;               /* bytes to copy */
-  uInt d;               /* distance back to copy from */
-  Byte *r;              /* copy source pointer */
-
-  /* load input, output, bit values */
-  LOAD
-
-  /* initialize masks */
-  ml = zlib_inflate_mask[bl];
-  md = zlib_inflate_mask[bd];
-
-  /* do until not enough input or output space for fast loop */
-  do {                          /* assume called with m >= 258 && n >= 10 */
-    /* get literal/length code */
-    GRABBITS(20)                /* max bits for literal/length code */
-    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
-    {
-      DUMPBITS(t->bits)
-      *q++ = (Byte)t->base;
-      m--;
-      continue;
-    }
+    struct inflate_state *state;
+    unsigned char *in;      /* local strm->next_in */
+    unsigned char *last;    /* while in < last, enough input available */
+    unsigned char *out;     /* local strm->next_out */
+    unsigned char *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const *lcode;      /* local strm->lencode */
+    code const *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code this;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    write = state->write;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
     do {
-      DUMPBITS(t->bits)
-      if (e & 16)
-      {
-        /* get extra bits for length */
-        e &= 15;
-        c = t->base + ((uInt)b & zlib_inflate_mask[e]);
-        DUMPBITS(e)
-
-        /* decode distance base of block to copy */
-        GRABBITS(15);           /* max bits for distance code */
-        e = (t = td + ((uInt)b & md))->exop;
-        do {
-          DUMPBITS(t->bits)
-          if (e & 16)
-          {
-            /* get extra bits to add to distance base */
-            e &= 15;
-            GRABBITS(e)         /* get extra bits (up to 13) */
-            d = t->base + ((uInt)b & zlib_inflate_mask[e]);
-            DUMPBITS(e)
-
-            /* do the copy */
-            m -= c;
-            r = q - d;
-            if (r < s->window)                  /* wrap if needed */
-            {
-              do {
-                r += s->end - s->window;        /* force pointer in window */
-              } while (r < s->window);          /* covers invalid distances */
-              e = s->end - r;
-              if (c > e)
-              {
-                c -= e;                         /* wrapped copy */
-                do {
-                    *q++ = *r++;
-                } while (--e);
-                r = s->window;
-                do {
-                    *q++ = *r++;
-                } while (--c);
-              }
-              else                              /* normal copy */
-              {
-                *q++ = *r++;  c--;
-                *q++ = *r++;  c--;
-                do {
-                    *q++ = *r++;
-                } while (--c);
-              }
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        this = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(this.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(this.op);
+        if (op == 0) {                          /* literal */
+            PUP(out) = (unsigned char)(this.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(this.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            this = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(this.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(this.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(this.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+                    from = window - OFF;
+                    if (write == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (write < op) {      /* wrap around window */
+                        from += wsize + write - op;
+                        op -= write;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (write < len) {  /* some from start of window */
+                                op = write;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += write - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                this = dcode[this.val + (hold & ((1U << op) - 1))];
+                goto dodist;
             }
-            else                                /* normal copy */
-            {
-              *q++ = *r++;  c--;
-              *q++ = *r++;  c--;
-              do {
-                *q++ = *r++;
-              } while (--c);
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
             }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            this = lcode[this.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            state->mode = TYPE;
             break;
-          }
-          else if ((e & 64) == 0)
-          {
-            t += t->base;
-            e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop;
-          }
-          else
-          {
-            z->msg = (char*)"invalid distance code";
-            UNGRAB
-            UPDATE
-            return Z_DATA_ERROR;
-          }
-        } while (1);
-        break;
-      }
-      if ((e & 64) == 0)
-      {
-        t += t->base;
-        if ((e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop) == 0)
-        {
-          DUMPBITS(t->bits)
-          *q++ = (Byte)t->base;
-          m--;
-          break;
         }
-      }
-      else if (e & 32)
-      {
-        UNGRAB
-        UPDATE
-        return Z_STREAM_END;
-      }
-      else
-      {
-        z->msg = (char*)"invalid literal/length code";
-        UNGRAB
-        UPDATE
-        return Z_DATA_ERROR;
-      }
-    } while (1);
-  } while (m >= 258 && n >= 10);
-
-  /* not enough input or output--restore pointers and return */
-  UNGRAB
-  UPDATE
-  return Z_OK;
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
 }
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and write == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
index fc720f0fa7f55ba8c8aa76ff13fe2bf2331cabf3..40315d9fddc4d6c893b25ec4e61f7e5617b7e241 100644 (file)
@@ -1,6 +1,6 @@
 /* inffast.h -- header to use inffast.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
 /* WARNING: this file should *not* be used by applications. It is
@@ -8,10 +8,4 @@
    subject to change. Applications should only use zlib.h.
  */
 
-extern int zlib_inflate_fast (
-    uInt,
-    uInt,
-    inflate_huft *,
-    inflate_huft *,
-    inflate_blocks_statef *,
-    z_streamp );
+void inflate_fast (z_streamp strm, unsigned start);
diff --git a/lib/zlib_inflate/inffixed.h b/lib/zlib_inflate/inffixed.h
new file mode 100644 (file)
index 0000000..75ed4b5
--- /dev/null
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
index 31b9e9054bf75c42b23b3b33ac80be795f63db63..7f922dccf1a5dd618c8553f4cf70cbd1ad2fd3b4 100644 (file)
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Based on zlib 1.2.3 but modified for the Linux Kernel by
+ * Richard Purdie <richard@openedhand.com>
+ *
+ * Changes mainly for static instead of dynamic memory allocation
+ *
  */
 
 #include <linux/zutil.h>
-#include "infblock.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
 #include "infutil.h"
 
 int zlib_inflate_workspacesize(void)
 {
-  return sizeof(struct inflate_workspace);
+    return sizeof(struct inflate_workspace);
 }
 
+int zlib_inflateReset(z_streamp strm)
+{
+    struct inflate_state *state;
+
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
 
-int zlib_inflateReset(
-       z_streamp z
-)
+    /* Initialise Window */
+    state->wsize = 1U << state->wbits;
+    state->write = 0;
+    state->whave = 0;
+
+    return Z_OK;
+}
+
+#if 0
+int zlib_inflatePrime(z_streamp strm, int bits, int value)
 {
-  if (z == NULL || z->state == NULL || z->workspace == NULL)
-    return Z_STREAM_ERROR;
-  z->total_in = z->total_out = 0;
-  z->msg = NULL;
-  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
-  zlib_inflate_blocks_reset(z->state->blocks, z, NULL);
-  return Z_OK;
+    struct inflate_state *state;
+
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
 }
+#endif
+
+int zlib_inflateInit2(z_streamp strm, int windowBits)
+{
+    struct inflate_state *state;
+
+    if (strm == NULL) return Z_STREAM_ERROR;
+    strm->msg = NULL;                 /* in case we return an error */
+
+    state = &WS(strm)->inflate_state;
+    strm->state = (struct internal_state *)state;
+
+    if (windowBits < 0) {
+        state->wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        state->wrap = (windowBits >> 4) + 1;
+    }
+    if (windowBits < 8 || windowBits > 15) {
+        return Z_STREAM_ERROR;
+    }
+    state->wbits = (unsigned)windowBits;
+    state->window = &WS(strm)->working_window[0];
 
+    return zlib_inflateReset(strm);
+}
 
-int zlib_inflateEnd(
-       z_streamp z
-)
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  This returns fixed tables from inffixed.h.
+ */
+static void zlib_fixedtables(struct inflate_state *state)
 {
-  if (z == NULL || z->state == NULL || z->workspace == NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->blocks != NULL)
-    zlib_inflate_blocks_free(z->state->blocks, z);
-  z->state = NULL;
-  return Z_OK;
+#   include "inffixed.h"
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
 }
 
 
-int zlib_inflateInit2_(
-       z_streamp z,
-       int w,
-       const char *version,
-       int stream_size
-)
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning. This is only called when a window is already in use, or when
+   output has been written during this inflate call, but the end of the deflate
+   stream has not been reached yet. It is also called to window dictionary data
+   when a dictionary is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+static void zlib_updatewindow(z_streamp strm, unsigned out)
 {
-  if (version == NULL || version[0] != ZLIB_VERSION[0] ||
-      stream_size != sizeof(z_stream) || z->workspace == NULL)
-      return Z_VERSION_ERROR;
-
-  /* initialize state */
-  z->msg = NULL;
-  z->state = &WS(z)->internal_state;
-  z->state->blocks = NULL;
-
-  /* handle undocumented nowrap option (no zlib header or check) */
-  z->state->nowrap = 0;
-  if (w < 0)
-  {
-    w = - w;
-    z->state->nowrap = 1;
-  }
-
-  /* set window size */
-  if (w < 8 || w > 15)
-  {
-    zlib_inflateEnd(z);
-    return Z_STREAM_ERROR;
-  }
-  z->state->wbits = (uInt)w;
-
-  /* create inflate_blocks state */
-  if ((z->state->blocks =
-      zlib_inflate_blocks_new(z, z->state->nowrap ? NULL : zlib_adler32, (uInt)1 << w))
-      == NULL)
-  {
-    zlib_inflateEnd(z);
-    return Z_MEM_ERROR;
-  }
-
-  /* reset state */
-  zlib_inflateReset(z);
-  return Z_OK;
+    struct inflate_state *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state *)strm->state;
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        memcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->write = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->write;
+        if (dist > copy) dist = copy;
+        memcpy(state->window + state->write, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            memcpy(state->window, strm->next_out - copy, copy);
+            state->write = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->write += dist;
+            if (state->write == state->wsize) state->write = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
 }
 
 
@@ -91,157 +150,764 @@ int zlib_inflateInit2_(
  * At the end of a Deflate-compressed PPP packet, we expect to have seen
  * a `stored' block type value but not the (zero) length bytes.
  */
-static int zlib_inflate_packet_flush(inflate_blocks_statef *s)
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+static int zlib_inflateSyncPacket(z_streamp strm)
 {
-    if (s->mode != LENS)
-       return Z_DATA_ERROR;
-    s->mode = TYPE;
+    struct inflate_state *state;
+
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+
+    if (state->mode == STORED && state->bits == 0) {
+       state->mode = TYPE;
+        return Z_OK;
+    }
+    return Z_DATA_ERROR;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#define UPDATE(check, buf, len) zlib_adler32(check, buf, len)
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int zlib_inflate(z_streamp strm, int flush)
+{
+    struct inflate_state *state;
+    unsigned char *next;    /* next input */
+    unsigned char *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == NULL || strm->state == NULL || strm->next_out == NULL ||
+        (strm->next_in == NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state *)strm->state;
+
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+            if (
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            strm->adler = state->check = zlib_adler32(0L, NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = zlib_adler32(0L, NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                zlib_fixedtables(state);
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            INITBITS();
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                memcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const *)(state->next);
+            state->lenbits = 7;
+            ret = zlib_inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const *)(state->next);
+            state->lenbits = 9;
+            ret = zlib_inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const *)(state->next);
+            state->distbits = 6;
+            ret = zlib_inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                break;
+            }
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+            if ((int)(this.op) == 0) {
+                state->mode = LIT;
+                break;
+            }
+            if (this.op & 32) {
+                state->mode = TYPE;
+                break;
+            }
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            if (state->offset > state->whave + out - left) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->write) {
+                    copy -= state->write;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->write - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call zlib_updatewindow() to create and/or update the window state.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        zlib_updatewindow(strm, out);
+
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+
+    if (flush == Z_PACKET_FLUSH && ret == Z_OK &&
+            (strm->avail_out != 0 || strm->avail_in == 0))
+               return zlib_inflateSyncPacket(strm);
+    return ret;
+}
+
+int zlib_inflateEnd(z_streamp strm)
+{
+    if (strm == NULL || strm->state == NULL)
+        return Z_STREAM_ERROR;
     return Z_OK;
 }
 
+#if 0
+int zlib_inflateSetDictionary(z_streamp strm, const Byte *dictionary,
+        uInt dictLength)
+{
+    struct inflate_state *state;
+    unsigned long id;
+
+    /* check state */
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id = zlib_adler32(0L, NULL, 0);
+        id = zlib_adler32(id, dictionary, dictLength);
+        if (id != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    zlib_updatewindow(strm, strm->avail_out);
 
-int zlib_inflateInit_(
-       z_streamp z,
-       const char *version,
-       int stream_size
-)
+    if (dictLength > state->wsize) {
+        memcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        memcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    return Z_OK;
+}
+#endif
+
+#if 0
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, zlib_syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+static unsigned zlib_syncsearch(unsigned *have, unsigned char *buf,
+        unsigned len)
 {
-  return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size);
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
 }
+#endif
 
-#undef NEEDBYTE
-#undef NEXTBYTE
-#define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;}
-#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+#if 0
+int zlib_inflateSync(z_streamp strm)
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state *state;
+
+    /* check parameters */
+    if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        zlib_syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = zlib_syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    zlib_inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+#endif
 
-int zlib_inflate(
-       z_streamp z,
-       int f
-)
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output but this should always be the case. The state must
+ * be waiting on the start of a block (i.e. mode == TYPE or HEAD).  On exit,
+ * the output will also be caught up, and the checksum will have been updated
+ * if need be.
+ */
+int zlib_inflateIncomp(z_stream *z)
 {
-  int r, trv;
-  uInt b;
-
-  if (z == NULL || z->state == NULL || z->next_in == NULL)
-    return Z_STREAM_ERROR;
-  trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
-  r = Z_BUF_ERROR;
-  while (1) switch (z->state->mode)
-  {
-    case METHOD:
-      NEEDBYTE
-      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"unknown compression method";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"invalid window size";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = FLAG;
-    case FLAG:
-      NEEDBYTE
-      b = NEXTBYTE;
-      if (((z->state->sub.method << 8) + b) % 31)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"incorrect header check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      if (!(b & PRESET_DICT))
-      {
-        z->state->mode = BLOCKS;
-        break;
-      }
-      z->state->mode = DICT4;
-    case DICT4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = DICT3;
-    case DICT3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = DICT2;
-    case DICT2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = DICT1;
-    case DICT1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-      z->adler = z->state->sub.check.need;
-      z->state->mode = DICT0;
-      return Z_NEED_DICT;
-    case DICT0:
-      z->state->mode = I_BAD;
-      z->msg = (char*)"need dictionary";
-      z->state->sub.marker = 0;       /* can try inflateSync */
-      return Z_STREAM_ERROR;
-    case BLOCKS:
-      r = zlib_inflate_blocks(z->state->blocks, z, r);
-      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
-         r = zlib_inflate_packet_flush(z->state->blocks);
-      if (r == Z_DATA_ERROR)
-      {
-        z->state->mode = I_BAD;
-        z->state->sub.marker = 0;       /* can try inflateSync */
-        break;
-      }
-      if (r == Z_OK)
-        r = trv;
-      if (r != Z_STREAM_END)
-        return r;
-      r = trv;
-      zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
-      if (z->state->nowrap)
-      {
-        z->state->mode = I_DONE;
-        break;
-      }
-      z->state->mode = CHECK4;
-    case CHECK4:
-      NEEDBYTE
-      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
-      z->state->mode = CHECK3;
-    case CHECK3:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
-      z->state->mode = CHECK2;
-    case CHECK2:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
-      z->state->mode = CHECK1;
-    case CHECK1:
-      NEEDBYTE
-      z->state->sub.check.need += (uLong)NEXTBYTE;
-
-      if (z->state->sub.check.was != z->state->sub.check.need)
-      {
-        z->state->mode = I_BAD;
-        z->msg = (char*)"incorrect data check";
-        z->state->sub.marker = 5;       /* can't try inflateSync */
-        break;
-      }
-      z->state->mode = I_DONE;
-    case I_DONE:
-      return Z_STREAM_END;
-    case I_BAD:
-      return Z_DATA_ERROR;
-    default:
-      return Z_STREAM_ERROR;
-  }
- empty:
-  if (f != Z_PACKET_FLUSH)
-    return r;
-  z->state->mode = I_BAD;
-  z->msg = (char *)"need more for packet flush";
-  z->state->sub.marker = 0;       /* can try inflateSync */
-  return Z_DATA_ERROR;
+    struct inflate_state *state = (struct inflate_state *)z->state;
+    Byte *saved_no = z->next_out;
+    uInt saved_ao = z->avail_out;
+
+    if (state->mode != TYPE && state->mode != HEAD)
+       return Z_DATA_ERROR;
+
+    /* Setup some variables to allow misuse of updateWindow */
+    z->avail_out = 0;
+    z->next_out = z->next_in + z->avail_in;
+
+    zlib_updatewindow(z, z->avail_in);
+
+    /* Restore saved variables */
+    z->avail_out = saved_ao;
+    z->next_out = saved_no;
+
+    z->adler = state->check =
+        UPDATE(state->check, z->next_in, z->avail_in);
+
+    z->total_out += z->avail_in;
+    z->total_in += z->avail_in;
+    z->next_in += z->avail_in;
+    state->total += z->avail_in;
+    z->avail_in = 0;
+
+    return Z_OK;
 }
diff --git a/lib/zlib_inflate/inflate.h b/lib/zlib_inflate/inflate.h
new file mode 100644 (file)
index 0000000..df8a6c9
--- /dev/null
@@ -0,0 +1,107 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN,        /* i: waiting for length/lit code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+        NAME -> COMMENT -> HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+    Read deflate blocks:
+            TYPE -> STORED or TABLE or LEN or CHECK
+            STORED -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN
+    Read deflate codes:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 7K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+ /*   gz_headerp head; */           /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const *lencode;    /* starting table for length/literal codes */
+    code const *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+};
index ef49738f57eca196c012508994883c0bf24911f5..2061d4f06765e614875c2d16f386c42a9dde0686 100644 (file)
@@ -12,8 +12,7 @@
 
 EXPORT_SYMBOL(zlib_inflate_workspacesize);
 EXPORT_SYMBOL(zlib_inflate);
-EXPORT_SYMBOL(zlib_inflateInit_);
-EXPORT_SYMBOL(zlib_inflateInit2_);
+EXPORT_SYMBOL(zlib_inflateInit2);
 EXPORT_SYMBOL(zlib_inflateEnd);
 EXPORT_SYMBOL(zlib_inflateReset);
 EXPORT_SYMBOL(zlib_inflateIncomp); 
diff --git a/lib/zlib_inflate/inflate_sync.c b/lib/zlib_inflate/inflate_sync.c
deleted file mode 100644 (file)
index 61411ff..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* inflate.c -- zlib interface to inflate modules
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-#include <linux/zutil.h>
-#include "infblock.h"
-#include "infutil.h"
-
-#if 0
-int zlib_inflateSync(
-       z_streamp z
-)
-{
-  uInt n;       /* number of bytes to look at */
-  Byte *p;      /* pointer to bytes */
-  uInt m;       /* number of marker bytes found in a row */
-  uLong r, w;   /* temporaries to save total_in and total_out */
-
-  /* set up */
-  if (z == NULL || z->state == NULL)
-    return Z_STREAM_ERROR;
-  if (z->state->mode != I_BAD)
-  {
-    z->state->mode = I_BAD;
-    z->state->sub.marker = 0;
-  }
-  if ((n = z->avail_in) == 0)
-    return Z_BUF_ERROR;
-  p = z->next_in;
-  m = z->state->sub.marker;
-
-  /* search */
-  while (n && m < 4)
-  {
-    static const Byte mark[4] = {0, 0, 0xff, 0xff};
-    if (*p == mark[m])
-      m++;
-    else if (*p)
-      m = 0;
-    else
-      m = 4 - m;
-    p++, n--;
-  }
-
-  /* restore */
-  z->total_in += p - z->next_in;
-  z->next_in = p;
-  z->avail_in = n;
-  z->state->sub.marker = m;
-
-  /* return no joy or set up to restart on a new block */
-  if (m != 4)
-    return Z_DATA_ERROR;
-  r = z->total_in;  w = z->total_out;
-  zlib_inflateReset(z);
-  z->total_in = r;  z->total_out = w;
-  z->state->mode = BLOCKS;
-  return Z_OK;
-}
-#endif  /*  0  */
-
-
-/* Returns true if inflate is currently at the end of a block generated
- * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
- * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
- * but removes the length bytes of the resulting empty stored block. When
- * decompressing, PPP checks that at the end of input packet, inflate is
- * waiting for these length bytes.
- */
-#if 0
-int zlib_inflateSyncPoint(
-       z_streamp z
-)
-{
-  if (z == NULL || z->state == NULL || z->state->blocks == NULL)
-    return Z_STREAM_ERROR;
-  return zlib_inflate_blocks_sync_point(z->state->blocks);
-}
-#endif  /*  0  */
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-static int zlib_inflate_addhistory(inflate_blocks_statef *s,
-                                     z_stream              *z)
-{
-    uLong b;              /* bit buffer */  /* NOT USED HERE */
-    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
-    uInt t;               /* temporary storage */
-    Byte *p;              /* input data pointer */
-    uInt n;               /* bytes available there */
-    Byte *q;              /* output window write pointer */
-    uInt m;               /* bytes to end of window or read pointer */
-
-    if (s->read != s->write)
-       return Z_STREAM_ERROR;
-    if (s->mode != TYPE)
-       return Z_DATA_ERROR;
-
-    /* we're ready to rock */
-    LOAD
-    /* while there is input ready, copy to output buffer, moving
-     * pointers as needed.
-     */
-    while (n) {
-       t = n;  /* how many to do */
-       /* is there room until end of buffer? */
-       if (t > m) t = m;
-       /* update check information */
-       if (s->checkfn != NULL)
-           s->check = (*s->checkfn)(s->check, q, t);
-       memcpy(q, p, t);
-       q += t;
-       p += t;
-       n -= t;
-       z->total_out += t;
-       s->read = q;    /* drag read pointer forward */
-/*      WWRAP  */      /* expand WWRAP macro by hand to handle s->read */
-       if (q == s->end) {
-           s->read = q = s->window;
-           m = WAVAIL;
-       }
-    }
-    UPDATE
-    return Z_OK;
-}
-
-
-/*
- * This subroutine adds the data at next_in/avail_in to the output history
- * without performing any output.  The output buffer must be "caught up";
- * i.e. no pending output (hence s->read equals s->write), and the state must
- * be BLOCKS (i.e. we should be willing to see the start of a series of
- * BLOCKS).  On exit, the output will also be caught up, and the checksum
- * will have been updated if need be.
- */
-
-int zlib_inflateIncomp(
-       z_stream *z
-
-)
-{
-    if (z->state->mode != BLOCKS)
-       return Z_DATA_ERROR;
-    return zlib_inflate_addhistory(z->state->blocks, z);
-}
index 874950ec48582e4b85c48ba6f1be7cb1f04cc659..62343c53bf7e671f2aa50e8e5e035e28b83ce906 100644 (file)
 /* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
 #include <linux/zutil.h>
 #include "inftrees.h"
-#include "infutil.h"
 
-static const char inflate_copyright[] __attribute_used__ =
-   " inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
 /*
   If you use the zlib library in a product, an acknowledgment is welcome
   in the documentation of your product. If for some reason you cannot
   include such an acknowledgment, I would appreciate that you keep this
   copyright string in the executable of your product.
  */
-struct internal_state;
-
-/* simplify the use of the inflate_huft type with some defines */
-#define exop word.what.Exop
-#define bits word.what.Bits
-
-
-static int huft_build (
-    uInt *,             /* code lengths in bits */
-    uInt,               /* number of codes */
-    uInt,               /* number of "simple" codes */
-    const uInt *,       /* list of base values for non-simple codes */
-    const uInt *,       /* list of extra bits for non-simple codes */
-    inflate_huft **,    /* result: starting table */
-    uInt *,             /* maximum lookup bits (returns actual) */
-    inflate_huft *,     /* space for trees */
-    uInt *,             /* hufts used in space */
-    uInt * );           /* space for values */
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* see note #13 above about 258 */
-static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
-static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-static const uInt cpdext[30] = { /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
 
 /*
-   Huffman code decoding is performed using a multi-level table lookup.
-   The fastest way to decode is to simply build a lookup table whose
-   size is determined by the longest code.  However, the time it takes
-   to build this table can also be a factor if the data being decoded
-   is not very long.  The most common codes are necessarily the
-   shortest codes, so those codes dominate the decoding time, and hence
-   the speed.  The idea is you can have a shorter table that decodes the
-   shorter, more probable codes, and then point to subsidiary tables for
-   the longer codes.  The time it costs to decode the longer codes is
-   then traded against the time it takes to make longer tables.
-
-   This results of this trade are in the variables lbits and dbits
-   below.  lbits is the number of bits the first level table for literal/
-   length codes can decode in one step, and dbits is the same thing for
-   the distance codes.  Subsequent tables are also less than or equal to
-   those sizes.  These values may be adjusted either when all of the
-   codes are shorter than that, in which case the longest code length in
-   bits is used, or when the shortest code is *longer* than the requested
-   table size, in which case the length of the shortest code in bits is
-   used.
-
-   There are two different values for the two tables, since they code a
-   different number of possibilities each.  The literal/length table
-   codes 286 possible values, or in a flat code, a little over eight
-   bits.  The distance table codes 30 possible values, or a little less
-   than five bits, flat.  The optimum values for speed end up being
-   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
-   The optimum values may differ though from machine to machine, and
-   possibly even between compilers.  Your mileage may vary.
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
  */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
-#define BMAX 15         /* maximum bit length of any code */
-
-static int huft_build(
-       uInt *b,               /* code lengths in bits (all assumed <= BMAX) */
-       uInt n,                /* number of codes (assumed <= 288) */
-       uInt s,                /* number of simple-valued codes (0..s-1) */
-       const uInt *d,         /* list of base values for non-simple codes */
-       const uInt *e,         /* list of extra bits for non-simple codes */
-       inflate_huft **t,      /* result: starting table */
-       uInt *m,               /* maximum lookup bits, returns actual */
-       inflate_huft *hp,      /* space for trees */
-       uInt *hn,              /* hufts used in space */
-       uInt *v                /* working area: values in order of bit length */
-)
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
-   if the given code set is incomplete (the tables are still built in this
-   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
-   lengths), or Z_MEM_ERROR if not enough memory. */
+int zlib_inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short *lens;
+unsigned codes;
+code **table;
+unsigned *bits;
+unsigned short *work;
 {
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code this;                  /* table entry for duplication */
+    code *next;             /* next available space in table */
+    const unsigned short *base;     /* base value table to use */
+    const unsigned short *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        this.op = (unsigned char)64;    /* invalid code marker */
+        this.bits = (unsigned char)1;
+        this.val = (unsigned short)0;
+        *(*table)++ = this;             /* make a table to force an error */
+        *(*table)++ = this;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min <= MAXBITS; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked when a LENS table is being made
+       against the space in *table, ENOUGH, minus the maximum space needed by
+       the worst case distance code, MAXD.  This should never happen, but the
+       sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+       This assumes that when type == LENS, bits == 9.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
 
-  uInt a;                       /* counter for codes of length k */
-  uInt c[BMAX+1];               /* bit length count table */
-  uInt f;                       /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register uInt i;              /* counter, current code */
-  register uInt j;              /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
-  register uInt *p;             /* pointer into c[], b[], or v[] */
-  inflate_huft *q;              /* points to current table */
-  struct inflate_huft_s r;      /* table entry for structure assignment */
-  inflate_huft *u[BMAX];        /* table stack */
-  register int w;               /* bits before this table == (l * h) */
-  uInt x[BMAX+1];               /* bit offsets, then code stack */
-  uInt *xp;                     /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  uInt z;                       /* number of entries in current table */
-
-
-  /* Generate counts for each bit length */
-  p = c;
-#define C0 *p++ = 0;
-#define C2 C0 C0 C0 C0
-#define C4 C2 C2 C2 C2
-  C4                            /* clear c[]--assume BMAX+1 is 16 */
-  p = b;  i = n;
-  do {
-    c[*p++]++;                  /* assume all entries <= BMAX */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = NULL;
-    *m = 0;
-    return Z_OK;
-  }
-
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((uInt)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((uInt)l > i)
-    l = i;
-  *m = l;
-
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return Z_DATA_ERROR;
-  if ((y -= c[i]) < 0)
-    return Z_DATA_ERROR;
-  c[i] += y;
-
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-  n = x[g];                     /* set n to length of v */
-
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = NULL;                  /* just to keep compilers happy */
-  q = NULL;                     /* ditto */
-  z = 0;                        /* ditto */
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-    a = c[k];
-    while (a--)
-    {
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = g - w;
-        z = z > (uInt)l ? l : z;        /* table size upper limit */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          if (j < z)
-            while (++j < z)     /* try smaller tables up to z bits */
-            {
-              if ((f <<= 1) <= *++xp)
-                break;          /* enough codes to use up j bits */
-              f -= *xp;         /* else deduct codes from patterns */
-            }
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if (type == LENS && used >= ENOUGH - MAXD)
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        this.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            this.op = (unsigned char)0;
+            this.val = work[sym];
         }
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate new table */
-        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
-          return Z_DATA_ERROR;  /* overflow of MANY */
-        u[h] = q = hp + *hn;
-        *hn += z;
-
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.bits = (Byte)l;     /* bits to dump before this table */
-          r.exop = (Byte)j;     /* bits in this table */
-          j = i >> (w - l);
-          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
-          u[h-1][j] = r;        /* connect to last table */
+        else if ((int)(work[sym]) > end) {
+            this.op = (unsigned char)(extra[work[sym]]);
+            this.val = base[work[sym]];
+        }
+        else {
+            this.op = (unsigned char)(32 + 64);         /* end of block */
+            this.val = 0;
         }
-        else
-          *t = q;               /* first table is returned result */
-      }
-
-      /* set up table entry in r */
-      r.bits = (Byte)(k - w);
-      if (p >= v + n)
-        r.exop = 128 + 64;      /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
-        r.base = *p++;          /* simple code is just the value */
-      }
-      else
-      {
-        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
-        r.base = d[*p++ - s];
-      }
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
-      while ((i & mask) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-        mask = (1 << w) - 1;
-      }
-    }
-  }
 
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = this;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
 
-  /* Return Z_BUF_ERROR if we were given an incomplete table */
-  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
-}
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
 
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
 
-int zlib_inflate_trees_bits(
-       uInt *c,                /* 19 code lengths */
-       uInt *bb,               /* bits tree desired/actual depth */
-       inflate_huft **tb,      /* bits tree result */
-       inflate_huft *hp,       /* space for trees */
-       z_streamp z             /* for messages */
-)
-{
-  int r;
-  uInt hn = 0;          /* hufts used in space */
-  uInt *v;              /* work area for huft_build */
-  
-  v = WS(z)->tree_work_area_1;
-  r = huft_build(c, 19, 19, NULL, NULL, tb, bb, hp, &hn, v);
-  if (r == Z_DATA_ERROR)
-    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
-  else if (r == Z_BUF_ERROR || *bb == 0)
-  {
-    z->msg = (char*)"incomplete dynamic bit lengths tree";
-    r = Z_DATA_ERROR;
-  }
-  return r;
-}
+            /* check for enough space */
+            used += 1U << curr;
+            if (type == LENS && used >= ENOUGH - MAXD)
+                return 1;
 
-int zlib_inflate_trees_dynamic(
-       uInt nl,                /* number of literal/length codes */
-       uInt nd,                /* number of distance codes */
-       uInt *c,                /* that many (total) code lengths */
-       uInt *bl,               /* literal desired/actual bit depth */
-       uInt *bd,               /* distance desired/actual bit depth */
-       inflate_huft **tl,      /* literal/length tree result */
-       inflate_huft **td,      /* distance tree result */
-       inflate_huft *hp,       /* space for trees */
-       z_streamp z             /* for messages */
-)
-{
-  int r;
-  uInt hn = 0;          /* hufts used in space */
-  uInt *v;              /* work area for huft_build */
-
-  /* allocate work area */
-  v = WS(z)->tree_work_area_2;
-
-  /* build literal/length tree */
-  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
-  if (r != Z_OK || *bl == 0)
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed literal/length tree";
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"incomplete literal/length tree";
-      r = Z_DATA_ERROR;
-    }
-    return r;
-  }
-
-  /* build distance tree */
-  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
-  if (r != Z_OK || (*bd == 0 && nl > 257))
-  {
-    if (r == Z_DATA_ERROR)
-      z->msg = (char*)"oversubscribed distance tree";
-    else if (r == Z_BUF_ERROR) {
-#ifdef PKZIP_BUG_WORKAROUND
-      r = Z_OK;
-    }
-#else
-      z->msg = (char*)"incomplete distance tree";
-      r = Z_DATA_ERROR;
-    }
-    else if (r != Z_MEM_ERROR)
-    {
-      z->msg = (char*)"empty distance tree with lengths";
-      r = Z_DATA_ERROR;
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
     }
-    return r;
-#endif
-  }
 
-  /* done */
-  return Z_OK;
-}
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    this.op = (unsigned char)64;                /* invalid code marker */
+    this.bits = (unsigned char)(len - drop);
+    this.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            this.bits = (unsigned char)len;
+        }
 
+        /* put invalid code marker in table */
+        next[huff >> drop] = this;
 
-int zlib_inflate_trees_fixed(
-       uInt *bl,                /* literal desired/actual bit depth */
-       uInt *bd,                /* distance desired/actual bit depth */
-       inflate_huft **tl,       /* literal/length tree result */
-       inflate_huft **td,       /* distance tree result */
-       inflate_huft *hp,       /* space for trees */
-       z_streamp z              /* for memory allocation */
-)
-{
-  int i;                /* temporary variable */
-  unsigned l[288];      /* length list for huft_build */
-  uInt *v;              /* work area for huft_build */
-
-  /* set up literal table */
-  for (i = 0; i < 144; i++)
-    l[i] = 8;
-  for (; i < 256; i++)
-    l[i] = 9;
-  for (; i < 280; i++)
-    l[i] = 7;
-  for (; i < 288; i++)          /* make a complete, but wrong code set */
-    l[i] = 8;
-  *bl = 9;
-  v = WS(z)->tree_work_area_1;
-  if ((i = huft_build(l, 288, 257, cplens, cplext, tl, bl, hp,  &i, v)) != 0)
-    return i;
-
-  /* set up distance table */
-  for (i = 0; i < 30; i++)      /* make an incomplete code set */
-    l[i] = 5;
-  *bd = 5;
-  if ((i = huft_build(l, 30, 0, cpdist, cpdext, td, bd, hp, &i, v)) > 1)
-    return i;
-
-  return Z_OK;
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
 }
index e37705adc008902e9e599dbc66744afadfd3554f..5f5219b1240e58c7b5eb2c7a9e2a3a7add446ef8 100644 (file)
@@ -1,6 +1,6 @@
 /* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
 /* WARNING: this file should *not* be used by applications. It is
@@ -8,57 +8,48 @@
    subject to change. Applications should only use zlib.h.
  */
 
-/* Huffman code lookup table entry--this entry is four bytes for machines
-   that have 16-bit pointers (e.g. PC's in the small or medium model). */
-
-#ifndef _INFTREES_H
-#define _INFTREES_H
-
-typedef struct inflate_huft_s inflate_huft;
-
-struct inflate_huft_s {
-  union {
-    struct {
-      Byte Exop;        /* number of extra bits or operation */
-      Byte Bits;        /* number of bits in this code or subcode */
-    } what;
-    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
-  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
-  uInt base;            /* literal, length base, distance base,
-                           or table offset */
-};
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
 
 /* Maximum size of dynamic tree.  The maximum found in a long but non-
-   exhaustive search was 1004 huft structures (850 for length/literals
-   and 154 for distances, the latter actually the result of an
-   exhaustive search).  The actual maximum is not known, but the
-   value below is more than safe. */
-#define MANY 1440
-
-extern int zlib_inflate_trees_bits (
-    uInt *,                     /* 19 code lengths */
-    uInt *,                     /* bits tree desired/actual depth */
-    inflate_huft **,            /* bits tree result */
-    inflate_huft *,             /* space for trees */
-    z_streamp);                 /* for messages */
-
-extern int zlib_inflate_trees_dynamic (
-    uInt,                       /* number of literal/length codes */
-    uInt,                       /* number of distance codes */
-    uInt *,                     /* that many (total) code lengths */
-    uInt *,                     /* literal desired/actual bit depth */
-    uInt *,                     /* distance desired/actual bit depth */
-    inflate_huft **,            /* literal/length tree result */
-    inflate_huft **,            /* distance tree result */
-    inflate_huft *,             /* space for trees */
-    z_streamp);                 /* for messages */
-
-extern int zlib_inflate_trees_fixed (
-    uInt *,                     /* literal desired/actual bit depth */
-    uInt *,                     /* distance desired/actual bit depth */
-    inflate_huft **,            /* literal/length tree result */
-    inflate_huft **,            /* distance tree result */
-    inflate_huft *,             /* space for trees */
-    z_streamp);                 /* for memory allocation */
-
-#endif /* _INFTREES_H */
+   exhaustive search was 1444 code structures (852 for length/literals
+   and 592 for distances, the latter actually the result of an
+   exhaustive search).  The true maximum is not known, but the value
+   below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+extern int zlib_inflate_table (codetype type, unsigned short *lens,
+                             unsigned codes, code **table,
+                             unsigned *bits, unsigned short *work);
diff --git a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c
deleted file mode 100644 (file)
index 00202b3..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* inflate_util.c -- data and routines common to blocks and codes
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h 
- */
-
-#include <linux/zutil.h>
-#include "infblock.h"
-#include "inftrees.h"
-#include "infcodes.h"
-#include "infutil.h"
-
-struct inflate_codes_state;
-
-/* And'ing with mask[n] masks the lower n bits */
-uInt zlib_inflate_mask[17] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-
-/* copy as much as possible from the sliding window to the output area */
-int zlib_inflate_flush(
-       inflate_blocks_statef *s,
-       z_streamp z,
-       int r
-)
-{
-  uInt n;
-  Byte *p;
-  Byte *q;
-
-  /* local copies of source and destination pointers */
-  p = z->next_out;
-  q = s->read;
-
-  /* compute number of bytes to copy as far as end of window */
-  n = (uInt)((q <= s->write ? s->write : s->end) - q);
-  if (n > z->avail_out) n = z->avail_out;
-  if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-  /* update counters */
-  z->avail_out -= n;
-  z->total_out += n;
-
-  /* update check information */
-  if (s->checkfn != NULL)
-    z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-  /* copy as far as end of window */
-  memcpy(p, q, n);
-  p += n;
-  q += n;
-
-  /* see if more to copy at beginning of window */
-  if (q == s->end)
-  {
-    /* wrap pointers */
-    q = s->window;
-    if (s->write == s->end)
-      s->write = s->window;
-
-    /* compute bytes to copy */
-    n = (uInt)(s->write - q);
-    if (n > z->avail_out) n = z->avail_out;
-    if (n && r == Z_BUF_ERROR) r = Z_OK;
-
-    /* update counters */
-    z->avail_out -= n;
-    z->total_out += n;
-
-    /* update check information */
-    if (s->checkfn != NULL)
-      z->adler = s->check = (*s->checkfn)(s->check, q, n);
-
-    /* copy */
-    memcpy(p, q, n);
-    p += n;
-    q += n;
-  }
-
-  /* update pointers */
-  z->next_out = p;
-  s->read = q;
-
-  /* done */
-  return r;
-}
index a15875fc5f7281afab71bc950ea705fac20f131e..eb1a9007bd866f204b25c74a2ec20855a6aa85c3 100644 (file)
 #ifndef _INFUTIL_H
 #define _INFUTIL_H
 
-#include <linux/zconf.h>
-#include "inftrees.h"
-#include "infcodes.h"
-
-typedef enum {
-      TYPE,     /* get type bits (3, including end bit) */
-      LENS,     /* get lengths for stored */
-      STORED,   /* processing stored block */
-      TABLE,    /* get table lengths */
-      BTREE,    /* get bit lengths tree for a dynamic block */
-      DTREE,    /* get length, distance trees for a dynamic block */
-      CODES,    /* processing fixed or dynamic block */
-      DRY,      /* output remaining window bytes */
-      B_DONE,   /* finished last block, done */
-      B_BAD}    /* got a data error--stuck here */
-inflate_block_mode;
-
-/* inflate blocks semi-private state */
-struct inflate_blocks_state {
-
-  /* mode */
-  inflate_block_mode  mode;     /* current inflate_block mode */
-
-  /* mode dependent information */
-  union {
-    uInt left;          /* if STORED, bytes left to copy */
-    struct {
-      uInt table;               /* table lengths (14 bits) */
-      uInt index;               /* index into blens (or border) */
-      uInt *blens;              /* bit lengths of codes */
-      uInt bb;                  /* bit length tree depth */
-      inflate_huft *tb;         /* bit length decoding tree */
-    } trees;            /* if DTREE, decoding info for trees */
-    struct {
-      inflate_codes_statef 
-         *codes;
-    } decode;           /* if CODES, current state */
-  } sub;                /* submode */
-  uInt last;            /* true if this block is the last block */
-
-  /* mode independent information */
-  uInt bitk;            /* bits in bit buffer */
-  uLong bitb;           /* bit buffer */
-  inflate_huft *hufts;  /* single malloc for tree space */
-  Byte *window;         /* sliding window */
-  Byte *end;            /* one byte after sliding window */
-  Byte *read;           /* window read pointer */
-  Byte *write;          /* window write pointer */
-  check_func checkfn;   /* check function */
-  uLong check;          /* check on output */
-
-};
-
-
-/* defines for inflate input/output */
-/*   update pointers and return */
-#define UPDBITS {s->bitb=b;s->bitk=k;}
-#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
-#define UPDOUT {s->write=q;}
-#define UPDATE {UPDBITS UPDIN UPDOUT}
-#define LEAVE {UPDATE return zlib_inflate_flush(s,z,r);}
-/*   get bytes and bits */
-#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
-#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
-#define NEXTBYTE (n--,*p++)
-#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
-#define DUMPBITS(j) {b>>=(j);k-=(j);}
-/*   output bytes */
-#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
-#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
-#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
-#define FLUSH {UPDOUT r=zlib_inflate_flush(s,z,r); LOADOUT}
-#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
-#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
-/*   load local pointers */
-#define LOAD {LOADIN LOADOUT}
-
-/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
-extern uInt zlib_inflate_mask[17];
-
-/* copy as much as possible from the sliding window to the output area */
-extern int zlib_inflate_flush (
-    inflate_blocks_statef *,
-    z_streamp ,
-    int);
-
-/* inflate private state */
-typedef enum {
-      METHOD,   /* waiting for method byte */
-      FLAG,     /* waiting for flag byte */
-      DICT4,    /* four dictionary check bytes to go */
-      DICT3,    /* three dictionary check bytes to go */
-      DICT2,    /* two dictionary check bytes to go */
-      DICT1,    /* one dictionary check byte to go */
-      DICT0,    /* waiting for inflateSetDictionary */
-      BLOCKS,   /* decompressing blocks */
-      CHECK4,   /* four check bytes to go */
-      CHECK3,   /* three check bytes to go */
-      CHECK2,   /* two check bytes to go */
-      CHECK1,   /* one check byte to go */
-      I_DONE,   /* finished check, done */
-      I_BAD}    /* got an error--stay here */
-inflate_mode;
-
-struct internal_state {
-
-  /* mode */
-  inflate_mode  mode;   /* current inflate mode */
-
-  /* mode dependent information */
-  union {
-    uInt method;        /* if FLAGS, method byte */
-    struct {
-      uLong was;                /* computed check value */
-      uLong need;               /* stream check value */
-    } check;            /* if CHECK, check values to compare */
-    uInt marker;        /* if BAD, inflateSync's marker bytes count */
-  } sub;        /* submode */
-
-  /* mode independent information */
-  int  nowrap;          /* flag for no wrapper */
-  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
-  inflate_blocks_statef 
-    *blocks;            /* current inflate_blocks state */
-
-};
-
-/* inflate codes private state */
-typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
-      START,    /* x: set up for LEN */
-      LEN,      /* i: get length/literal/eob next */
-      LENEXT,   /* i: getting length extra (have base) */
-      DIST,     /* i: get distance next */
-      DISTEXT,  /* i: getting distance extra */
-      COPY,     /* o: copying bytes in window, waiting for space */
-      LIT,      /* o: got literal, waiting for output space */
-      WASH,     /* o: got eob, possibly still output waiting */
-      END,      /* x: got eob and all data flushed */
-      BADCODE}  /* x: got error */
-inflate_codes_mode;
-
-struct inflate_codes_state {
-
-  /* mode */
-  inflate_codes_mode mode;      /* current inflate_codes mode */
-
-  /* mode dependent information */
-  uInt len;
-  union {
-    struct {
-      inflate_huft *tree;       /* pointer into tree */
-      uInt need;                /* bits needed */
-    } code;             /* if LEN or DIST, where in tree */
-    uInt lit;           /* if LIT, literal */
-    struct {
-      uInt get;                 /* bits to get for extra */
-      uInt dist;                /* distance back to copy from */
-    } copy;             /* if EXT or COPY, where and how much */
-  } sub;                /* submode */
-
-  /* mode independent information */
-  Byte lbits;           /* ltree bits decoded per branch */
-  Byte dbits;           /* dtree bits decoder per branch */
-  inflate_huft *ltree;          /* literal/length/eob tree */
-  inflate_huft *dtree;          /* distance tree */
-
-};
+#include <linux/zlib.h>
 
 /* memory allocation for inflation */
 
 struct inflate_workspace {
-       inflate_codes_statef working_state;
-       struct inflate_blocks_state working_blocks_state;
-       struct internal_state internal_state;
-       unsigned int tree_work_area_1[19];
-       unsigned int tree_work_area_2[288];
-       unsigned working_blens[258 + 0x1f + 0x1f];
-       inflate_huft working_hufts[MANY];
+       struct inflate_state inflate_state;
        unsigned char working_window[1 << MAX_WBITS];
 };
 
index 64f6da0f422e2ceff980ea0a7117fb9b75d9be10..6de4a4a5eb13d879dda5748ff306d85dc07c610e 100644 (file)
@@ -860,7 +860,7 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz
 }
 
 #ifdef CONFIG_KEYS
-static inline int dummy_key_alloc(struct key *key)
+static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx)
 {
        return 0;
 }
index 3fdc49c6a02cde37607fbf792bfc2068fd773860..51f8515573894f93103c802cad0173e7f53e23b2 100644 (file)
@@ -247,8 +247,8 @@ static inline void key_alloc_serial(struct key *key)
  *   instantiate the key or discard it before returning
  */
 struct key *key_alloc(struct key_type *type, const char *desc,
-                     uid_t uid, gid_t gid, key_perm_t perm,
-                     int not_in_quota)
+                     uid_t uid, gid_t gid, struct task_struct *ctx,
+                     key_perm_t perm, int not_in_quota)
 {
        struct key_user *user = NULL;
        struct key *key;
@@ -318,7 +318,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 #endif
 
        /* let the security module know about the key */
-       ret = security_key_alloc(key);
+       ret = security_key_alloc(key, ctx);
        if (ret < 0)
                goto security_error;
 
@@ -822,7 +822,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 
        /* allocate a new key */
        key = key_alloc(ktype, description, current->fsuid, current->fsgid,
-                       perm, not_in_quota);
+                       current, perm, not_in_quota);
        if (IS_ERR(key)) {
                key_ref = ERR_PTR(PTR_ERR(key));
                goto error_3;
@@ -907,6 +907,10 @@ void key_revoke(struct key *key)
         * it */
        down_write(&key->sem);
        set_bit(KEY_FLAG_REVOKED, &key->flags);
+
+       if (key->type->revoke)
+               key->type->revoke(key);
+
        up_write(&key->sem);
 
 } /* end key_revoke() */
index bffa924c1f88240b088e5c30ee7d9363849c45e2..1357207fc9df8d55c783704d4e8f0a79c0465b32 100644 (file)
@@ -240,13 +240,14 @@ static long keyring_read(const struct key *keyring,
  * allocate a keyring and link into the destination keyring
  */
 struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
-                         int not_in_quota, struct key *dest)
+                         struct task_struct *ctx, int not_in_quota,
+                         struct key *dest)
 {
        struct key *keyring;
        int ret;
 
        keyring = key_alloc(&key_type_keyring, description,
-                           uid, gid,
+                           uid, gid, ctx,
                            (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
                            not_in_quota);
 
index 217a0bef3c82b341db5c07d414b7385a8f4a00fb..4d9825f9962cb027e5f610380177d2722d60aca0 100644 (file)
@@ -67,7 +67,8 @@ struct key root_session_keyring = {
 /*
  * allocate the keyrings to be associated with a UID
  */
-int alloc_uid_keyring(struct user_struct *user)
+int alloc_uid_keyring(struct user_struct *user,
+                     struct task_struct *ctx)
 {
        struct key *uid_keyring, *session_keyring;
        char buf[20];
@@ -76,7 +77,7 @@ int alloc_uid_keyring(struct user_struct *user)
        /* concoct a default session keyring */
        sprintf(buf, "_uid_ses.%u", user->uid);
 
-       session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
+       session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, NULL);
        if (IS_ERR(session_keyring)) {
                ret = PTR_ERR(session_keyring);
                goto error;
@@ -86,7 +87,7 @@ int alloc_uid_keyring(struct user_struct *user)
         * keyring */
        sprintf(buf, "_uid.%u", user->uid);
 
-       uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0,
+       uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0,
                                    session_keyring);
        if (IS_ERR(uid_keyring)) {
                key_put(session_keyring);
@@ -143,7 +144,7 @@ int install_thread_keyring(struct task_struct *tsk)
 
        sprintf(buf, "_tid.%u", tsk->pid);
 
-       keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+       keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
@@ -177,7 +178,7 @@ int install_process_keyring(struct task_struct *tsk)
        if (!tsk->signal->process_keyring) {
                sprintf(buf, "_pid.%u", tsk->tgid);
 
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error;
@@ -217,7 +218,7 @@ static int install_session_keyring(struct task_struct *tsk,
        if (!keyring) {
                sprintf(buf, "_ses.%u", tsk->tgid);
 
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
                if (IS_ERR(keyring))
                        return PTR_ERR(keyring);
        }
@@ -390,6 +391,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
        struct request_key_auth *rka;
        key_ref_t key_ref, ret, err;
 
+       might_sleep();
+
        /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
         * searchable, but we failed to find a key or we found a negative key;
         * otherwise we want to return a sample error (probably -EACCES) if
@@ -495,27 +498,35 @@ key_ref_t search_process_keyrings(struct key_type *type,
         */
        if (context->request_key_auth &&
            context == current &&
-           type != &key_type_request_key_auth &&
-           key_validate(context->request_key_auth) == 0
+           type != &key_type_request_key_auth
            ) {
-               rka = context->request_key_auth->payload.data;
+               /* defend against the auth key being revoked */
+               down_read(&context->request_key_auth->sem);
 
-               key_ref = search_process_keyrings(type, description, match,
-                                                 rka->context);
+               if (key_validate(context->request_key_auth) == 0) {
+                       rka = context->request_key_auth->payload.data;
 
-               if (!IS_ERR(key_ref))
-                       goto found;
+                       key_ref = search_process_keyrings(type, description,
+                                                         match, rka->context);
 
-               switch (PTR_ERR(key_ref)) {
-               case -EAGAIN: /* no key */
-                       if (ret)
+                       up_read(&context->request_key_auth->sem);
+
+                       if (!IS_ERR(key_ref))
+                               goto found;
+
+                       switch (PTR_ERR(key_ref)) {
+                       case -EAGAIN: /* no key */
+                               if (ret)
+                                       break;
+                       case -ENOKEY: /* negative key */
+                               ret = key_ref;
                                break;
-               case -ENOKEY: /* negative key */
-                       ret = key_ref;
-                       break;
-               default:
-                       err = key_ref;
-                       break;
+                       default:
+                               err = key_ref;
+                               break;
+                       }
+               } else {
+                       up_read(&context->request_key_auth->sem);
                }
        }
 
@@ -717,7 +728,7 @@ long join_session_keyring(const char *name)
        keyring = find_keyring_by_name(name, 0);
        if (PTR_ERR(keyring) == -ENOKEY) {
                /* not found - try and create a new one */
-               keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
+               keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 0, NULL);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error2;
index f030a0ccbb93f9f70f95cc44833dd48dd6b7e469..eab66a06ca53528f6d8d195aaa84856baa69e7aa 100644 (file)
@@ -48,7 +48,8 @@ static int call_sbin_request_key(struct key *key,
        /* allocate a new session keyring */
        sprintf(desc, "_req.%u", key->serial);
 
-       keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+       keyring = keyring_alloc(desc, current->fsuid, current->fsgid,
+                               current, 1, NULL);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error_alloc;
@@ -137,7 +138,8 @@ static struct key *__request_key_construction(struct key_type *type,
 
        /* create a key and add it to the queue */
        key = key_alloc(type, description,
-                       current->fsuid, current->fsgid, KEY_POS_ALL, 0);
+                       current->fsuid, current->fsgid,
+                       current, KEY_POS_ALL, 0);
        if (IS_ERR(key))
                goto alloc_failed;
 
index cce6ba6b032352aa4cd182db51a521242eea814a..cb9817ced3fd8ce3419bf52d449f6b191d8bbed4 100644 (file)
@@ -20,6 +20,7 @@
 
 static int request_key_auth_instantiate(struct key *, const void *, size_t);
 static void request_key_auth_describe(const struct key *, struct seq_file *);
+static void request_key_auth_revoke(struct key *);
 static void request_key_auth_destroy(struct key *);
 static long request_key_auth_read(const struct key *, char __user *, size_t);
 
@@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = {
        .def_datalen    = sizeof(struct request_key_auth),
        .instantiate    = request_key_auth_instantiate,
        .describe       = request_key_auth_describe,
+       .revoke         = request_key_auth_revoke,
        .destroy        = request_key_auth_destroy,
        .read           = request_key_auth_read,
 };
@@ -91,6 +93,24 @@ static long request_key_auth_read(const struct key *key,
 
 } /* end request_key_auth_read() */
 
+/*****************************************************************************/
+/*
+ * handle revocation of an authorisation token key
+ * - called with the key sem write-locked
+ */
+static void request_key_auth_revoke(struct key *key)
+{
+       struct request_key_auth *rka = key->payload.data;
+
+       kenter("{%d}", key->serial);
+
+       if (rka->context) {
+               put_task_struct(rka->context);
+               rka->context = NULL;
+       }
+
+} /* end request_key_auth_revoke() */
+
 /*****************************************************************************/
 /*
  * destroy an instantiation authorisation token key
@@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key)
 
        kenter("{%d}", key->serial);
 
+       if (rka->context) {
+               put_task_struct(rka->context);
+               rka->context = NULL;
+       }
+
        key_put(rka->target_key);
        kfree(rka);
 
@@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
         * another process */
        if (current->request_key_auth) {
                /* it is - use that instantiation context here too */
+               down_read(&current->request_key_auth->sem);
+
+               /* if the auth key has been revoked, then the key we're
+                * servicing is already instantiated */
+               if (test_bit(KEY_FLAG_REVOKED,
+                            &current->request_key_auth->flags))
+                       goto auth_key_revoked;
+
                irka = current->request_key_auth->payload.data;
                rka->context = irka->context;
                rka->pid = irka->pid;
+               get_task_struct(rka->context);
+
+               up_read(&current->request_key_auth->sem);
        }
        else {
                /* it isn't - use this process as the context */
                rka->context = current;
                rka->pid = current->pid;
+               get_task_struct(rka->context);
        }
 
        rka->target_key = key_get(target);
@@ -148,7 +185,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
        sprintf(desc, "%x", target->serial);
 
        authkey = key_alloc(&key_type_request_key_auth, desc,
-                           current->fsuid, current->fsgid,
+                           current->fsuid, current->fsgid, current,
                            KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
                            KEY_USR_VIEW, 1);
        if (IS_ERR(authkey)) {
@@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
        if (ret < 0)
                goto error_inst;
 
-       kleave(" = {%d})", authkey->serial);
+       kleave(" = {%d}", authkey->serial);
        return authkey;
 
+auth_key_revoked:
+       up_read(&current->request_key_auth->sem);
+       kfree(rka);
+       kleave("= -EKEYREVOKED");
+       return ERR_PTR(-EKEYREVOKED);
+
 error_inst:
        key_revoke(authkey);
        key_put(authkey);
index 54adc9d31e9248ae3b1ca00ed0cc166a533c814e..524915dfda646302c3d76049f844fdd534c49001 100644 (file)
@@ -4252,6 +4252,57 @@ static int selinux_setprocattr(struct task_struct *p,
        return size;
 }
 
+#ifdef CONFIG_KEYS
+
+static int selinux_key_alloc(struct key *k, struct task_struct *tsk)
+{
+       struct task_security_struct *tsec = tsk->security;
+       struct key_security_struct *ksec;
+
+       ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
+       if (!ksec)
+               return -ENOMEM;
+
+       ksec->obj = k;
+       ksec->sid = tsec->sid;
+       k->security = ksec;
+
+       return 0;
+}
+
+static void selinux_key_free(struct key *k)
+{
+       struct key_security_struct *ksec = k->security;
+
+       k->security = NULL;
+       kfree(ksec);
+}
+
+static int selinux_key_permission(key_ref_t key_ref,
+                           struct task_struct *ctx,
+                           key_perm_t perm)
+{
+       struct key *key;
+       struct task_security_struct *tsec;
+       struct key_security_struct *ksec;
+
+       key = key_ref_to_ptr(key_ref);
+
+       tsec = ctx->security;
+       ksec = key->security;
+
+       /* if no specific permissions are requested, we skip the
+          permission check. No serious, additional covert channels
+          appear to be created. */
+       if (perm == 0)
+               return 0;
+
+       return avc_has_perm(tsec->sid, ksec->sid,
+                           SECCLASS_KEY, perm, NULL);
+}
+
+#endif
+
 static struct security_operations selinux_ops = {
        .ptrace =                       selinux_ptrace,
        .capget =                       selinux_capget,
@@ -4406,6 +4457,12 @@ static struct security_operations selinux_ops = {
        .xfrm_state_delete_security =   selinux_xfrm_state_delete,
        .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,
 #endif
+
+#ifdef CONFIG_KEYS
+       .key_alloc =                    selinux_key_alloc,
+       .key_free =                     selinux_key_free,
+       .key_permission =               selinux_key_permission,
+#endif
 };
 
 static __init int selinux_init(void)
@@ -4441,6 +4498,13 @@ static __init int selinux_init(void)
        } else {
                printk(KERN_INFO "SELinux:  Starting in permissive mode\n");
        }
+
+#ifdef CONFIG_KEYS
+       /* Add security information to initial keyrings */
+       security_key_alloc(&root_user_keyring, current);
+       security_key_alloc(&root_session_keyring, current);
+#endif
+
        return 0;
 }
 
index 70ee65a588170f48041de266f142520873b01c9b..bc020bde6c8644d2a77415c162b5c7032d5fff14 100644 (file)
    S_(SECCLASS_PACKET, PACKET__SEND, "send")
    S_(SECCLASS_PACKET, PACKET__RECV, "recv")
    S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
+   S_(SECCLASS_KEY, KEY__VIEW, "view")
+   S_(SECCLASS_KEY, KEY__READ, "read")
+   S_(SECCLASS_KEY, KEY__WRITE, "write")
+   S_(SECCLASS_KEY, KEY__SEARCH, "search")
+   S_(SECCLASS_KEY, KEY__LINK, "link")
+   S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
index 1d9cf3d306bc95069c43235131acf6cef4be392d..1205227a3a33acb6dc5e3f5115eb1d60794d905a 100644 (file)
 #define PACKET__SEND                              0x00000001UL
 #define PACKET__RECV                              0x00000002UL
 #define PACKET__RELABELTO                         0x00000004UL
+
+#define KEY__VIEW                                 0x00000001UL
+#define KEY__READ                                 0x00000002UL
+#define KEY__WRITE                                0x00000004UL
+#define KEY__SEARCH                               0x00000008UL
+#define KEY__LINK                                 0x00000010UL
+#define KEY__SETATTR                              0x00000020UL
+
index 3aec75fee4f7b723fa5b02c634d51fc33ce5a7b7..24303b61309f431ea3811a6cce27c7ef49a241c8 100644 (file)
@@ -60,3 +60,4 @@
     S_("netlink_kobject_uevent_socket")
     S_("appletalk_socket")
     S_("packet")
+    S_("key")
index a0eb9e281d185f886de232cbc8ad37795d653cf1..95887aed2a68069285d754bfe635144b232159e9 100644 (file)
@@ -62,6 +62,7 @@
 #define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET           55
 #define SECCLASS_APPLETALK_SOCKET                        56
 #define SECCLASS_PACKET                                  57
+#define SECCLASS_KEY                                     58
 
 /*
  * Security identifier indices for initial entities
index 54c03077888214a37c0cfd88be4d87575d2377f4..8f5547ad185664595664f6a54a61e0f5642966c5 100644 (file)
@@ -99,6 +99,11 @@ struct sk_security_struct {
        u32 peer_sid;                   /* SID of peer */
 };
 
+struct key_security_struct {
+       struct key *obj; /* back pointer */
+       u32 sid;         /* SID of key */
+};
+
 extern unsigned int selinux_checkreqprot;
 
 #endif /* _SELINUX_OBJSEC_H_ */
index b65ee4701f98fab7d6564d9cee6d771455aa3603..e0d791a9845246b907fde876d441b46852c4268f 100644 (file)
@@ -58,6 +58,8 @@ source "sound/pci/Kconfig"
 
 source "sound/ppc/Kconfig"
 
+source "sound/aoa/Kconfig"
+
 source "sound/arm/Kconfig"
 
 source "sound/mips/Kconfig"
index f352bb23596880a7e40c6ca58cdb93bcd9e852f5..a682ea30f0c949bccd79c2199c5603c36498aa22 100644 (file)
@@ -4,7 +4,7 @@
 obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ aoa/
 
 ifeq ($(CONFIG_SND),y)
   obj-y += last.o
diff --git a/sound/aoa/Kconfig b/sound/aoa/Kconfig
new file mode 100644 (file)
index 0000000..a85194f
--- /dev/null
@@ -0,0 +1,17 @@
+menu "Apple Onboard Audio driver"
+       depends on SND!=n && PPC
+
+config SND_AOA
+       tristate "Apple Onboard Audio driver"
+       depends on SOUND && SND_PCM
+       ---help---
+       This option enables the new driver for the various
+       Apple Onboard Audio components.
+
+source "sound/aoa/fabrics/Kconfig"
+
+source "sound/aoa/codecs/Kconfig"
+
+source "sound/aoa/soundbus/Kconfig"
+
+endmenu
diff --git a/sound/aoa/Makefile b/sound/aoa/Makefile
new file mode 100644 (file)
index 0000000..d8de3e7
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_SND_AOA) += core/
+obj-$(CONFIG_SND_AOA) += codecs/
+obj-$(CONFIG_SND_AOA) += fabrics/
+obj-$(CONFIG_SND_AOA_SOUNDBUS) += soundbus/
diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h
new file mode 100644 (file)
index 0000000..3a61f31
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Apple Onboard Audio GPIO definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#ifndef __AOA_GPIO_H
+#define __AOA_GPIO_H
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <asm/prom.h>
+
+typedef void (*notify_func_t)(void *data);
+
+enum notify_type {
+       AOA_NOTIFY_HEADPHONE,
+       AOA_NOTIFY_LINE_IN,
+       AOA_NOTIFY_LINE_OUT,
+};
+
+struct gpio_runtime;
+struct gpio_methods {
+       /* for initialisation/de-initialisation of the GPIO layer */
+       void (*init)(struct gpio_runtime *rt);
+       void (*exit)(struct gpio_runtime *rt);
+
+       /* turn off headphone, speakers, lineout */
+       void (*all_amps_off)(struct gpio_runtime *rt);
+       /* turn headphone, speakers, lineout back to previous setting */
+       void (*all_amps_restore)(struct gpio_runtime *rt);
+
+       void (*set_headphone)(struct gpio_runtime *rt, int on);
+       void (*set_speakers)(struct gpio_runtime *rt, int on);
+       void (*set_lineout)(struct gpio_runtime *rt, int on);
+
+       int (*get_headphone)(struct gpio_runtime *rt);
+       int (*get_speakers)(struct gpio_runtime *rt);
+       int (*get_lineout)(struct gpio_runtime *rt);
+
+       void (*set_hw_reset)(struct gpio_runtime *rt, int on);
+
+       /* use this to be notified of any events. The notification
+        * function is passed the data, and is called in process
+        * context by the use of schedule_work.
+        * The interface for it is that setting a function to NULL
+        * removes it, and they return 0 if the operation succeeded,
+        * and -EBUSY if the notification is already assigned by
+        * someone else. */
+       int (*set_notify)(struct gpio_runtime *rt,
+                         enum notify_type type,
+                         notify_func_t notify,
+                         void *data);
+       /* returns 0 if not plugged in, 1 if plugged in
+        * or a negative error code */
+       int (*get_detect)(struct gpio_runtime *rt,
+                         enum notify_type type);
+};
+
+struct gpio_notification {
+       notify_func_t notify;
+       void *data;
+       void *gpio_private;
+       struct work_struct work;
+       struct mutex mutex;
+};
+
+struct gpio_runtime {
+       /* to be assigned by fabric */
+       struct device_node *node;
+       /* since everyone needs this pointer anyway... */
+       struct gpio_methods *methods;
+       /* to be used by the gpio implementation */
+       int implementation_private;
+       struct gpio_notification headphone_notify;
+       struct gpio_notification line_in_notify;
+       struct gpio_notification line_out_notify;
+};
+
+#endif /* __AOA_GPIO_H */
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h
new file mode 100644 (file)
index 0000000..378ef1e
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Apple Onboard Audio definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#ifndef __AOA_H
+#define __AOA_H
+#include <asm/prom.h>
+#include <linux/module.h>
+/* So apparently there's a reason for requiring driver.h to be included first! */
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/asound.h>
+#include <sound/control.h>
+#include "aoa-gpio.h"
+#include "soundbus/soundbus.h"
+
+#define MAX_CODEC_NAME_LEN     32
+
+struct aoa_codec {
+       char    name[MAX_CODEC_NAME_LEN];
+
+       struct module *owner;
+
+       /* called when the fabric wants to init this codec.
+        * Do alsa card manipulations from here. */
+       int (*init)(struct aoa_codec *codec);
+
+       /* called when the fabric is done with the codec.
+        * The alsa card will be cleaned up so don't bother. */
+       void (*exit)(struct aoa_codec *codec);
+
+       /* May be NULL, but can be used by the fabric.
+        * Refcounting is the codec driver's responsibility */
+       struct device_node *node;
+
+       /* assigned by fabric before init() is called, points
+        * to the soundbus device. Cannot be NULL. */
+       struct soundbus_dev *soundbus_dev;
+
+       /* assigned by the fabric before init() is called, points
+        * to the fabric's gpio runtime record for the relevant
+        * device. */
+       struct gpio_runtime *gpio;
+
+       /* assigned by the fabric before init() is called, contains
+        * a codec specific bitmask of what outputs and inputs are
+        * actually connected */
+       u32 connected;
+
+       /* data the fabric can associate with this structure */
+       void *fabric_data;
+
+       /* private! */
+       struct list_head list;
+       struct aoa_fabric *fabric;
+};
+
+/* return 0 on success */
+extern int
+aoa_codec_register(struct aoa_codec *codec);
+extern void
+aoa_codec_unregister(struct aoa_codec *codec);
+
+#define MAX_LAYOUT_NAME_LEN    32
+
+struct aoa_fabric {
+       char    name[MAX_LAYOUT_NAME_LEN];
+
+       struct module *owner;
+
+       /* once codecs register, they are passed here after.
+        * They are of course not initialised, since the
+        * fabric is responsible for initialising some fields
+        * in the codec structure! */
+       int (*found_codec)(struct aoa_codec *codec);
+       /* called for each codec when it is removed,
+        * also in the case that aoa_fabric_unregister
+        * is called and all codecs are removed
+        * from this fabric.
+        * Also called if found_codec returned 0 but
+        * the codec couldn't initialise. */
+       void (*remove_codec)(struct aoa_codec *codec);
+       /* If found_codec returned 0, and the codec
+        * could be initialised, this is called. */
+       void (*attached_codec)(struct aoa_codec *codec);
+};
+
+/* return 0 on success, -EEXIST if another fabric is
+ * registered, -EALREADY if the same fabric is registered.
+ * Passing NULL can be used to test for the presence
+ * of another fabric, if -EALREADY is returned there is
+ * no other fabric present.
+ * In the case that the function returns -EALREADY
+ * and the fabric passed is not NULL, all codecs
+ * that are not assigned yet are passed to the fabric
+ * again for reconsideration. */
+extern int
+aoa_fabric_register(struct aoa_fabric *fabric);
+
+/* it is vital to call this when the fabric exits!
+ * When calling, the remove_codec will be called
+ * for all codecs, unless it is NULL. */
+extern void
+aoa_fabric_unregister(struct aoa_fabric *fabric);
+
+/* if for some reason you want to get rid of a codec
+ * before the fabric is removed, use this.
+ * Note that remove_codec is called for it! */
+extern void
+aoa_fabric_unlink_codec(struct aoa_codec *codec);
+
+/* alsa help methods */
+struct aoa_card {
+       struct snd_card *alsa_card;
+};
+        
+extern int aoa_snd_device_new(snd_device_type_t type,
+       void * device_data, struct snd_device_ops * ops);
+extern struct snd_card *aoa_get_card(void);
+extern int aoa_snd_ctl_add(struct snd_kcontrol* control);
+
+/* GPIO stuff */
+extern struct gpio_methods *pmf_gpio_methods;
+extern struct gpio_methods *ftr_gpio_methods;
+/* extern struct gpio_methods *map_gpio_methods; */
+
+#endif /* __AOA_H */
diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig
new file mode 100644 (file)
index 0000000..90cf58f
--- /dev/null
@@ -0,0 +1,32 @@
+config SND_AOA_ONYX
+       tristate "support Onyx chip"
+       depends on SND_AOA
+       ---help---
+       This option enables support for the Onyx (pcm3052)
+       codec chip found in the latest Apple machines
+       (most of those with digital audio output).
+
+#config SND_AOA_TOPAZ
+#      tristate "support Topaz chips"
+#      depends on SND_AOA
+#      ---help---
+#      This option enables support for the Topaz (CS84xx)
+#      codec chips found in the latest Apple machines,
+#      these chips do the digital input and output on
+#      some PowerMacs.
+
+config SND_AOA_TAS
+       tristate "support TAS chips"
+       depends on SND_AOA
+       ---help---
+       This option enables support for the tas chips
+       found in a lot of Apple Machines, especially
+       iBooks and PowerBooks without digital.
+
+config SND_AOA_TOONIE
+       tristate "support Toonie chip"
+       depends on SND_AOA
+       ---help---
+       This option enables support for the toonie codec
+       found in the Mac Mini. If you have a Mac Mini and
+       want to hear sound, select this option.
diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile
new file mode 100644 (file)
index 0000000..31cbe68
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o
+obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o
+obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
new file mode 100644 (file)
index 0000000..0b76507
--- /dev/null
@@ -0,0 +1,1113 @@
+/*
+ * Apple Onboard Audio driver for Onyx codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This is a driver for the pcm3052 codec chip (codenamed Onyx)
+ * that is present in newer Apple hardware (with digital output).
+ *
+ * The Onyx codec has the following connections (listed by the bit
+ * to be used in aoa_codec.connected):
+ *  0: analog output
+ *  1: digital output
+ *  2: line input
+ *  3: microphone input
+ * Note that even though I know of no machine that has for example
+ * the digital output connected but not the analog, I have handled
+ * all the different cases in the code so that this driver may serve
+ * as a good example of what to do.
+ *
+ * NOTE: This driver assumes that there's at most one chip to be
+ *      used with one alsa card, in form of creating all kinds
+ *      of mixer elements without regard for their existence.
+ *      But snd-aoa assumes that there's at most one card, so
+ *      this means you can only have one onyx on a system. This
+ *      should probably be fixed by changing the assumption of
+ *      having just a single card on a system, and making the
+ *      'card' pointer accessible to anyone who needs it instead
+ *      of hiding it in the aoa_snd_* functions...
+ *
+ */
+#include <linux/delay.h>
+#include <linux/module.h>
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
+
+#include "snd-aoa-codec-onyx.h"
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+
+#define PFX "snd-aoa-codec-onyx: "
+
+struct onyx {
+       /* cache registers 65 to 80, they are write-only! */
+       u8                      cache[16];
+       struct i2c_client       i2c;
+       struct aoa_codec        codec;
+       u32                     initialised:1,
+                               spdif_locked:1,
+                               analog_locked:1,
+                               original_mute:2;
+       int                     open_count;
+       struct codec_info       *codec_info;
+
+       /* mutex serializes concurrent access to the device
+        * and this structure.
+        */
+       struct mutex mutex;
+};
+#define codec_to_onyx(c) container_of(c, struct onyx, codec)
+
+/* both return 0 if all ok, else on error */
+static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value)
+{
+       s32 v;
+
+       if (reg != ONYX_REG_CONTROL) {
+               *value = onyx->cache[reg-FIRSTREGISTER];
+               return 0;
+       }
+       v = i2c_smbus_read_byte_data(&onyx->i2c, reg);
+       if (v < 0)
+               return -1;
+       *value = (u8)v;
+       onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value;
+       return 0;
+}
+
+static int onyx_write_register(struct onyx *onyx, u8 reg, u8 value)
+{
+       int result;
+
+       result = i2c_smbus_write_byte_data(&onyx->i2c, reg, value);
+       if (!result)
+               onyx->cache[reg-FIRSTREGISTER] = value;
+       return result;
+}
+
+/* alsa stuff */
+
+static int onyx_dev_register(struct snd_device *dev)
+{
+       return 0;
+}
+
+static struct snd_device_ops ops = {
+       .dev_register = onyx_dev_register,
+};
+
+/* this is necessary because most alsa mixer programs
+ * can't properly handle the negative range */
+#define VOLUME_RANGE_SHIFT     128
+
+static int onyx_snd_vol_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = -128 + VOLUME_RANGE_SHIFT;
+       uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT;
+       return 0;
+}
+
+static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       s8 l, r;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+       mutex_unlock(&onyx->mutex);
+
+       ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
+       ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
+
+       return 0;
+}
+
+static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       s8 l, r;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+       onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+
+       if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
+           r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
+               mutex_unlock(&onyx->mutex);
+               return 0;
+       }
+
+       onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
+                           ucontrol->value.integer.value[0]
+                            - VOLUME_RANGE_SHIFT);
+       onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
+                           ucontrol->value.integer.value[1]
+                            - VOLUME_RANGE_SHIFT);
+       mutex_unlock(&onyx->mutex);
+
+       return 1;
+}
+
+static struct snd_kcontrol_new volume_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Master Playback Volume",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = onyx_snd_vol_info,
+       .get = onyx_snd_vol_get,
+       .put = onyx_snd_vol_put,
+};
+
+/* like above, this is necessary because a lot
+ * of alsa mixer programs don't handle ranges
+ * that don't start at 0 properly.
+ * even alsamixer is one of them... */
+#define INPUTGAIN_RANGE_SHIFT  (-3)
+
+static int onyx_snd_inputgain_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT;
+       uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT;
+       return 0;
+}
+
+static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 ig;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
+       mutex_unlock(&onyx->mutex);
+
+       ucontrol->value.integer.value[0] =
+               (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
+
+       return 0;
+}
+
+static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 v, n;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+       n = v;
+       n &= ~ONYX_ADC_PGA_GAIN_MASK;
+       n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
+               & ONYX_ADC_PGA_GAIN_MASK;
+       onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
+       mutex_unlock(&onyx->mutex);
+
+       return n != v;
+}
+
+static struct snd_kcontrol_new inputgain_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Master Capture Volume",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = onyx_snd_inputgain_info,
+       .get = onyx_snd_inputgain_get,
+       .put = onyx_snd_inputgain_put,
+};
+
+static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = { "Line-In", "Microphone" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item > 1)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       s8 v;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+       mutex_unlock(&onyx->mutex);
+
+       ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
+
+       return 0;
+}
+
+static void onyx_set_capture_source(struct onyx *onyx, int mic)
+{
+       s8 v;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+       v &= ~ONYX_ADC_INPUT_MIC;
+       if (mic)
+               v |= ONYX_ADC_INPUT_MIC;
+       onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
+       mutex_unlock(&onyx->mutex);
+}
+
+static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       onyx_set_capture_source(snd_kcontrol_chip(kcontrol),
+                               ucontrol->value.enumerated.item[0]);
+       return 1;
+}
+
+static struct snd_kcontrol_new capture_source_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       /* If we name this 'Input Source', it properly shows up in
+        * alsamixer as a selection, * but it's shown under the 
+        * 'Playback' category.
+        * If I name it 'Capture Source', it shows up in strange
+        * ways (two bools of which one can be selected at a
+        * time) but at least it's shown in the 'Capture'
+        * category.
+        * I was told that this was due to backward compatibility,
+        * but I don't understand then why the mangling is *not*
+        * done when I name it "Input Source".....
+        */
+       .name = "Capture Source",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = onyx_snd_capture_source_info,
+       .get = onyx_snd_capture_source_get,
+       .put = onyx_snd_capture_source_put,
+};
+
+static int onyx_snd_mute_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 c;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
+       mutex_unlock(&onyx->mutex);
+
+       ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
+       ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
+
+       return 0;
+}
+
+static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 v = 0, c = 0;
+       int err = -EBUSY;
+
+       mutex_lock(&onyx->mutex);
+       if (onyx->analog_locked)
+               goto out_unlock;
+
+       onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+       c = v;
+       c &= ~(ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT);
+       if (!ucontrol->value.integer.value[0])
+               c |= ONYX_MUTE_LEFT;
+       if (!ucontrol->value.integer.value[1])
+               c |= ONYX_MUTE_RIGHT;
+       err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
+
+ out_unlock:
+       mutex_unlock(&onyx->mutex);
+
+       return !err ? (v != c) : err;
+}
+
+static struct snd_kcontrol_new mute_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Master Playback Switch",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = onyx_snd_mute_info,
+       .get = onyx_snd_mute_get,
+       .put = onyx_snd_mute_put,
+};
+
+
+static int onyx_snd_single_bit_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+#define FLAG_POLARITY_INVERT   1
+#define FLAG_SPDIFLOCK         2
+
+static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 c;
+       long int pv = kcontrol->private_value;
+       u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;
+       u8 address = (pv >> 8) & 0xff;
+       u8 mask = pv & 0xff;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, address, &c);
+       mutex_unlock(&onyx->mutex);
+
+       ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
+
+       return 0;
+}
+
+static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 v = 0, c = 0;
+       int err;
+       long int pv = kcontrol->private_value;
+       u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;
+       u8 spdiflock = (pv >> 16) & FLAG_SPDIFLOCK;
+       u8 address = (pv >> 8) & 0xff;
+       u8 mask = pv & 0xff;
+
+       mutex_lock(&onyx->mutex);
+       if (spdiflock && onyx->spdif_locked) {
+               /* even if alsamixer doesn't care.. */
+               err = -EBUSY;
+               goto out_unlock;
+       }
+       onyx_read_register(onyx, address, &v);
+       c = v;
+       c &= ~(mask);
+       if (!!ucontrol->value.integer.value[0] ^ polarity)
+               c |= mask;
+       err = onyx_write_register(onyx, address, c);
+
+ out_unlock:
+       mutex_unlock(&onyx->mutex);
+
+       return !err ? (v != c) : err;
+}
+
+#define SINGLE_BIT(n, type, description, address, mask, flags)         \
+static struct snd_kcontrol_new n##_control = {                         \
+       .iface = SNDRV_CTL_ELEM_IFACE_##type,                           \
+       .name = description,                                            \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,                      \
+       .info = onyx_snd_single_bit_info,                               \
+       .get = onyx_snd_single_bit_get,                                 \
+       .put = onyx_snd_single_bit_put,                                 \
+       .private_value = (flags << 16) | (address << 8) | mask          \
+}
+
+SINGLE_BIT(spdif,
+          MIXER,
+          SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
+          ONYX_REG_DIG_INFO4,
+          ONYX_SPDIF_ENABLE,
+          FLAG_SPDIFLOCK);
+SINGLE_BIT(ovr1,
+          MIXER,
+          "Oversampling Rate",
+          ONYX_REG_DAC_CONTROL,
+          ONYX_OVR1,
+          0);
+SINGLE_BIT(flt0,
+          MIXER,
+          "Fast Digital Filter Rolloff",
+          ONYX_REG_DAC_FILTER,
+          ONYX_ROLLOFF_FAST,
+          FLAG_POLARITY_INVERT);
+SINGLE_BIT(hpf,
+          MIXER,
+          "Highpass Filter",
+          ONYX_REG_ADC_HPF_BYPASS,
+          ONYX_HPF_DISABLE,
+          FLAG_POLARITY_INVERT);
+SINGLE_BIT(dm12,
+          MIXER,
+          "Digital De-Emphasis",
+          ONYX_REG_DAC_DEEMPH,
+          ONYX_DIGDEEMPH_CTRL,
+          0);
+
+static int onyx_spdif_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+       return 0;
+}
+
+static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       /* datasheet page 30, all others are 0 */
+       ucontrol->value.iec958.status[0] = 0x3e;
+       ucontrol->value.iec958.status[1] = 0xff;
+
+       ucontrol->value.iec958.status[3] = 0x3f;
+       ucontrol->value.iec958.status[4] = 0x0f;
+       
+       return 0;
+}
+
+static struct snd_kcontrol_new onyx_spdif_mask = {
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+       .info =         onyx_spdif_info,
+       .get =          onyx_spdif_mask_get,
+};
+
+static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 v;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+       ucontrol->value.iec958.status[0] = v & 0x3e;
+
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO2, &v);
+       ucontrol->value.iec958.status[1] = v;
+
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);
+       ucontrol->value.iec958.status[3] = v & 0x3f;
+
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+       ucontrol->value.iec958.status[4] = v & 0x0f;
+       mutex_unlock(&onyx->mutex);
+
+       return 0;
+}
+
+static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+       u8 v;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+       v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
+       onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
+
+       v = ucontrol->value.iec958.status[1];
+       onyx_write_register(onyx, ONYX_REG_DIG_INFO2, v);
+
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);
+       v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f);
+       onyx_write_register(onyx, ONYX_REG_DIG_INFO3, v);
+
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+       v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
+       onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+       mutex_unlock(&onyx->mutex);
+
+       return 1;
+}
+
+static struct snd_kcontrol_new onyx_spdif_ctrl = {
+       .access =       SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+       .info =         onyx_spdif_info,
+       .get =          onyx_spdif_get,
+       .put =          onyx_spdif_put,
+};
+
+/* our registers */
+
+static u8 register_map[] = {
+       ONYX_REG_DAC_ATTEN_LEFT,
+       ONYX_REG_DAC_ATTEN_RIGHT,
+       ONYX_REG_CONTROL,
+       ONYX_REG_DAC_CONTROL,
+       ONYX_REG_DAC_DEEMPH,
+       ONYX_REG_DAC_FILTER,
+       ONYX_REG_DAC_OUTPHASE,
+       ONYX_REG_ADC_CONTROL,
+       ONYX_REG_ADC_HPF_BYPASS,
+       ONYX_REG_DIG_INFO1,
+       ONYX_REG_DIG_INFO2,
+       ONYX_REG_DIG_INFO3,
+       ONYX_REG_DIG_INFO4
+};
+
+static u8 initial_values[ARRAY_SIZE(register_map)] = {
+       0x80, 0x80, /* muted */
+       ONYX_MRST | ONYX_SRST, /* but handled specially! */
+       ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT,
+       0, /* no deemphasis */
+       ONYX_DAC_FILTER_ALWAYS,
+       ONYX_OUTPHASE_INVERTED,
+       (-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/
+       ONYX_ADC_HPF_ALWAYS,
+       (1<<2), /* pcm audio */
+       2,      /* category: pcm coder */
+       0,      /* sampling frequency 44.1 kHz, clock accuracy level II */
+       1       /* 24 bit depth */
+};
+
+/* reset registers of chip, either to initial or to previous values */
+static int onyx_register_init(struct onyx *onyx)
+{
+       int i;
+       u8 val;
+       u8 regs[sizeof(initial_values)];
+
+       if (!onyx->initialised) {
+               memcpy(regs, initial_values, sizeof(initial_values));
+               if (onyx_read_register(onyx, ONYX_REG_CONTROL, &val))
+                       return -1;
+               val &= ~ONYX_SILICONVERSION;
+               val |= initial_values[3];
+               regs[3] = val;
+       } else {
+               for (i=0; i<sizeof(register_map); i++)
+                       regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER];
+       }
+
+       for (i=0; i<sizeof(register_map); i++) {
+               if (onyx_write_register(onyx, register_map[i], regs[i]))
+                       return -1;
+       }
+       onyx->initialised = 1;
+       return 0;
+}
+
+static struct transfer_info onyx_transfers[] = {
+       /* this is first so we can skip it if no input is present...
+        * No hardware exists with that, but it's here as an example
+        * of what to do :) */
+       {
+               /* analog input */
+               .formats = SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_S16_BE |
+                          SNDRV_PCM_FMTBIT_S24_BE,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .transfer_in = 1,
+               .must_be_clock_source = 0,
+               .tag = 0,
+       },
+       {
+               /* if analog and digital are currently off, anything should go,
+                * so this entry describes everything we can do... */
+               .formats = SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_S16_BE |
+                          SNDRV_PCM_FMTBIT_S24_BE
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+                          | SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+#endif
+               ,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .tag = 0,
+       },
+       {
+               /* analog output */
+               .formats = SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_S16_BE |
+                          SNDRV_PCM_FMTBIT_S24_BE,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .transfer_in = 0,
+               .must_be_clock_source = 0,
+               .tag = 1,
+       },
+       {
+               /* digital pcm output, also possible for analog out */
+               .formats = SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_S16_BE |
+                          SNDRV_PCM_FMTBIT_S24_BE,
+               .rates = SNDRV_PCM_RATE_32000 |
+                        SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000,
+               .transfer_in = 0,
+               .must_be_clock_source = 0,
+               .tag = 2,
+       },
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+Once alsa gets supports for this kind of thing we can add it...
+       {
+               /* digital compressed output */
+               .formats =  SNDRV_PCM_FMTBIT_COMPRESSED_16BE,
+               .rates = SNDRV_PCM_RATE_32000 |
+                        SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000,
+               .tag = 2,
+       },
+#endif
+       {}
+};
+
+static int onyx_usable(struct codec_info_item *cii,
+                      struct transfer_info *ti,
+                      struct transfer_info *out)
+{
+       u8 v;
+       struct onyx *onyx = cii->codec_data;
+       int spdif_enabled, analog_enabled;
+
+       mutex_lock(&onyx->mutex);
+       onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+       spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
+       onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+       analog_enabled = 
+               (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
+                != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
+       mutex_unlock(&onyx->mutex);
+
+       switch (ti->tag) {
+       case 0: return 1;
+       case 1: return analog_enabled;
+       case 2: return spdif_enabled;
+       }
+       return 1;
+}
+
+static int onyx_prepare(struct codec_info_item *cii,
+                       struct bus_info *bi,
+                       struct snd_pcm_substream *substream)
+{
+       u8 v;
+       struct onyx *onyx = cii->codec_data;
+       int err = -EBUSY;
+
+       mutex_lock(&onyx->mutex);
+
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+       if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
+               /* mute and lock analog output */
+               onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+               if (onyx_write_register(onyx
+                                       ONYX_REG_DAC_CONTROL,
+                                       v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
+                       goto out_unlock;
+               onyx->analog_locked = 1;
+               err = 0;
+               goto out_unlock;
+       }
+#endif
+       switch (substream->runtime->rate) {
+       case 32000:
+       case 44100:
+       case 48000:
+               /* these rates are ok for all outputs */
+               /* FIXME: program spdif channel control bits here so that
+                *        userspace doesn't have to if it only plays pcm! */
+               err = 0;
+               goto out_unlock;
+       default:
+               /* got some rate that the digital output can't do,
+                * so disable and lock it */
+               onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v);
+               if (onyx_write_register(onyx,
+                                       ONYX_REG_DIG_INFO4,
+                                       v & ~ONYX_SPDIF_ENABLE))
+                       goto out_unlock;
+               onyx->spdif_locked = 1;
+               err = 0;
+               goto out_unlock;
+       }
+
+ out_unlock:
+       mutex_unlock(&onyx->mutex);
+
+       return err;
+}
+
+static int onyx_open(struct codec_info_item *cii,
+                    struct snd_pcm_substream *substream)
+{
+       struct onyx *onyx = cii->codec_data;
+
+       mutex_lock(&onyx->mutex);
+       onyx->open_count++;
+       mutex_unlock(&onyx->mutex);
+
+       return 0;
+}
+
+static int onyx_close(struct codec_info_item *cii,
+                     struct snd_pcm_substream *substream)
+{
+       struct onyx *onyx = cii->codec_data;
+
+       mutex_lock(&onyx->mutex);
+       onyx->open_count--;
+       if (!onyx->open_count)
+               onyx->spdif_locked = onyx->analog_locked = 0;
+       mutex_unlock(&onyx->mutex);
+
+       return 0;
+}
+
+static int onyx_switch_clock(struct codec_info_item *cii,
+                            enum clock_switch what)
+{
+       struct onyx *onyx = cii->codec_data;
+
+       mutex_lock(&onyx->mutex);
+       /* this *MUST* be more elaborate later... */
+       switch (what) {
+       case CLOCK_SWITCH_PREPARE_SLAVE:
+               onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio);
+               break;
+       case CLOCK_SWITCH_SLAVE:
+               onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio);
+               break;
+       default: /* silence warning */
+               break;
+       }
+       mutex_unlock(&onyx->mutex);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int onyx_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+       struct onyx *onyx = cii->codec_data;
+       u8 v;
+       int err = -ENXIO;
+
+       mutex_lock(&onyx->mutex);
+       if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+               goto out_unlock;
+       onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
+       /* Apple does a sleep here but the datasheet says to do it on resume */
+       err = 0;
+ out_unlock:
+       mutex_unlock(&onyx->mutex);
+
+       return err;
+}
+
+static int onyx_resume(struct codec_info_item *cii)
+{
+       struct onyx *onyx = cii->codec_data;
+       u8 v;
+       int err = -ENXIO;
+
+       mutex_lock(&onyx->mutex);
+       /* take codec out of suspend */
+       if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+               goto out_unlock;
+       onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
+       /* FIXME: should divide by sample rate, but 8k is the lowest we go */
+       msleep(2205000/8000);
+       /* reset all values */
+       onyx_register_init(onyx);
+       err = 0;
+ out_unlock:
+       mutex_unlock(&onyx->mutex);
+
+       return err;
+}
+
+#endif /* CONFIG_PM */
+
+static struct codec_info onyx_codec_info = {
+       .transfers = onyx_transfers,
+       .sysclock_factor = 256,
+       .bus_factor = 64,
+       .owner = THIS_MODULE,
+       .usable = onyx_usable,
+       .prepare = onyx_prepare,
+       .open = onyx_open,
+       .close = onyx_close,
+       .switch_clock = onyx_switch_clock,
+#ifdef CONFIG_PM
+       .suspend = onyx_suspend,
+       .resume = onyx_resume,
+#endif
+};
+
+static int onyx_init_codec(struct aoa_codec *codec)
+{
+       struct onyx *onyx = codec_to_onyx(codec);
+       struct snd_kcontrol *ctl;
+       struct codec_info *ci = &onyx_codec_info;
+       u8 v;
+       int err;
+
+       if (!onyx->codec.gpio || !onyx->codec.gpio->methods) {
+               printk(KERN_ERR PFX "gpios not assigned!!\n");
+               return -EINVAL;
+       }
+
+       onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+       msleep(1);
+       onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
+       msleep(1);
+       onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+       msleep(1);
+       
+       if (onyx_register_init(onyx)) {
+               printk(KERN_ERR PFX "failed to initialise onyx registers\n");
+               return -ENODEV;
+       }
+
+       if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, onyx, &ops)) {
+               printk(KERN_ERR PFX "failed to create onyx snd device!\n");
+               return -ENODEV;
+       }
+
+       /* nothing connected? what a joke! */
+       if ((onyx->codec.connected & 0xF) == 0)
+               return -ENOTCONN;
+
+       /* if no inputs are present... */
+       if ((onyx->codec.connected & 0xC) == 0) {
+               if (!onyx->codec_info)
+                       onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);
+               if (!onyx->codec_info)
+                       return -ENOMEM;
+               ci = onyx->codec_info;
+               *ci = onyx_codec_info;
+               ci->transfers++;
+       }
+
+       /* if no outputs are present... */
+       if ((onyx->codec.connected & 3) == 0) {
+               if (!onyx->codec_info)
+                       onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);
+               if (!onyx->codec_info)
+                       return -ENOMEM;
+               ci = onyx->codec_info;
+               /* this is fine as there have to be inputs
+                * if we end up in this part of the code */
+               *ci = onyx_codec_info;
+               ci->transfers[1].formats = 0;
+       }
+
+       if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev,
+                                                  aoa_get_card(),
+                                                  ci, onyx)) {
+               printk(KERN_ERR PFX "error creating onyx pcm\n");
+               return -ENODEV;
+       }
+#define ADDCTL(n)                                                      \
+       do {                                                            \
+               ctl = snd_ctl_new1(&n, onyx);                           \
+               if (ctl) {                                              \
+                       ctl->id.device =                                \
+                               onyx->codec.soundbus_dev->pcm->device;  \
+                       err = aoa_snd_ctl_add(ctl);                     \
+                       if (err)                                        \
+                               goto error;                             \
+               }                                                       \
+       } while (0)
+
+       if (onyx->codec.soundbus_dev->pcm) {
+               /* give the user appropriate controls
+                * depending on what inputs are connected */
+               if ((onyx->codec.connected & 0xC) == 0xC)
+                       ADDCTL(capture_source_control);
+               else if (onyx->codec.connected & 4)
+                       onyx_set_capture_source(onyx, 0);
+               else
+                       onyx_set_capture_source(onyx, 1);
+               if (onyx->codec.connected & 0xC)
+                       ADDCTL(inputgain_control);
+
+               /* depending on what output is connected,
+                * give the user appropriate controls */
+               if (onyx->codec.connected & 1) {
+                       ADDCTL(volume_control);
+                       ADDCTL(mute_control);
+                       ADDCTL(ovr1_control);
+                       ADDCTL(flt0_control);
+                       ADDCTL(hpf_control);
+                       ADDCTL(dm12_control);
+                       /* spdif control defaults to off */
+               }
+               if (onyx->codec.connected & 2) {
+                       ADDCTL(onyx_spdif_mask);
+                       ADDCTL(onyx_spdif_ctrl);
+               }
+               if ((onyx->codec.connected & 3) == 3)
+                       ADDCTL(spdif_control);
+               /* if only S/PDIF is connected, enable it unconditionally */
+               if ((onyx->codec.connected & 3) == 2) {
+                       onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+                       v |= ONYX_SPDIF_ENABLE;
+                       onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+               }
+       }
+#undef ADDCTL
+       printk(KERN_INFO PFX "attached to onyx codec via i2c\n");
+
+       return 0;
+ error:
+       onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
+       snd_device_free(aoa_get_card(), onyx);
+       return err;
+}
+
+static void onyx_exit_codec(struct aoa_codec *codec)
+{
+       struct onyx *onyx = codec_to_onyx(codec);
+
+       if (!onyx->codec.soundbus_dev) {
+               printk(KERN_ERR PFX "onyx_exit_codec called without soundbus_dev!\n");
+               return;
+       }
+       onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
+}
+
+static struct i2c_driver onyx_driver;
+
+static int onyx_create(struct i2c_adapter *adapter,
+                      struct device_node *node,
+                      int addr)
+{
+       struct onyx *onyx;
+       u8 dummy;
+
+       onyx = kzalloc(sizeof(struct onyx), GFP_KERNEL);
+
+       if (!onyx)
+               return -ENOMEM;
+
+       mutex_init(&onyx->mutex);
+       onyx->i2c.driver = &onyx_driver;
+       onyx->i2c.adapter = adapter;
+       onyx->i2c.addr = addr & 0x7f;
+       strlcpy(onyx->i2c.name, "onyx audio codec", I2C_NAME_SIZE-1);
+
+       if (i2c_attach_client(&onyx->i2c)) {
+               printk(KERN_ERR PFX "failed to attach to i2c\n");
+               goto fail;
+       }
+
+       /* we try to read from register ONYX_REG_CONTROL
+        * to check if the codec is present */
+       if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) {
+               i2c_detach_client(&onyx->i2c);
+               printk(KERN_ERR PFX "failed to read control register\n");
+               goto fail;
+       }
+
+       strlcpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN-1);
+       onyx->codec.owner = THIS_MODULE;
+       onyx->codec.init = onyx_init_codec;
+       onyx->codec.exit = onyx_exit_codec;
+       onyx->codec.node = of_node_get(node);
+
+       if (aoa_codec_register(&onyx->codec)) {
+               i2c_detach_client(&onyx->i2c);
+               goto fail;
+       }
+       printk(KERN_DEBUG PFX "created and attached onyx instance\n");
+       return 0;
+ fail:
+       kfree(onyx);
+       return -EINVAL;
+}
+
+static int onyx_i2c_attach(struct i2c_adapter *adapter)
+{
+       struct device_node *busnode, *dev = NULL;
+       struct pmac_i2c_bus *bus;
+
+       bus = pmac_i2c_adapter_to_bus(adapter);
+       if (bus == NULL)
+               return -ENODEV;
+       busnode = pmac_i2c_get_bus_node(bus);
+
+       while ((dev = of_get_next_child(busnode, dev)) != NULL) {
+               if (device_is_compatible(dev, "pcm3052")) {
+                       u32 *addr;
+                       printk(KERN_DEBUG PFX "found pcm3052\n");
+                       addr = (u32 *) get_property(dev, "reg", NULL);
+                       if (!addr)
+                               return -ENODEV;
+                       return onyx_create(adapter, dev, (*addr)>>1);
+               }
+       }
+
+       /* if that didn't work, try desperate mode for older
+        * machines that have stuff missing from the device tree */
+       
+       if (!device_is_compatible(busnode, "k2-i2c"))
+               return -ENODEV;
+
+       printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
+       /* probe both possible addresses for the onyx chip */
+       if (onyx_create(adapter, NULL, 0x46) == 0)
+               return 0;
+       return onyx_create(adapter, NULL, 0x47);
+}
+
+static int onyx_i2c_detach(struct i2c_client *client)
+{
+       struct onyx *onyx = container_of(client, struct onyx, i2c);
+       int err;
+
+       if ((err = i2c_detach_client(client)))
+               return err;
+       aoa_codec_unregister(&onyx->codec);
+       of_node_put(onyx->codec.node);
+       if (onyx->codec_info)
+               kfree(onyx->codec_info);
+       kfree(onyx);
+       return 0;
+}
+
+static struct i2c_driver onyx_driver = {
+       .driver = {
+               .name = "aoa_codec_onyx",
+               .owner = THIS_MODULE,
+       },
+       .attach_adapter = onyx_i2c_attach,
+       .detach_client = onyx_i2c_detach,
+};
+
+static int __init onyx_init(void)
+{
+       return i2c_add_driver(&onyx_driver);
+}
+
+static void __exit onyx_exit(void)
+{
+       i2c_del_driver(&onyx_driver);
+}
+
+module_init(onyx_init);
+module_exit(onyx_exit);
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.h b/sound/aoa/codecs/snd-aoa-codec-onyx.h
new file mode 100644 (file)
index 0000000..aeedda7
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Apple Onboard Audio driver for Onyx codec (header)
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __SND_AOA_CODEC_ONYX_H
+#define __SND_AOA_CODEC_ONYX_H
+#include <stddef.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <asm/pmac_low_i2c.h>
+#include <asm/prom.h>
+
+/* PCM3052 register definitions */
+
+/* the attenuation registers take values from
+ * -1 (0dB) to -127 (-63.0 dB) or others (muted) */
+#define ONYX_REG_DAC_ATTEN_LEFT                65
+#define FIRSTREGISTER                  ONYX_REG_DAC_ATTEN_LEFT
+#define ONYX_REG_DAC_ATTEN_RIGHT       66
+
+#define ONYX_REG_CONTROL               67
+#      define ONYX_MRST                (1<<7)
+#      define ONYX_SRST                (1<<6)
+#      define ONYX_ADPSV               (1<<5)
+#      define ONYX_DAPSV               (1<<4)
+#      define ONYX_SILICONVERSION      (1<<0)
+/* all others reserved */
+
+#define ONYX_REG_DAC_CONTROL           68
+#      define ONYX_OVR1                (1<<6)
+#      define ONYX_MUTE_RIGHT          (1<<1)
+#      define ONYX_MUTE_LEFT           (1<<0)
+
+#define ONYX_REG_DAC_DEEMPH            69
+#      define ONYX_DIGDEEMPH_SHIFT     5
+#      define ONYX_DIGDEEMPH_MASK      (3<<ONYX_DIGDEEMPH_SHIFT)
+#      define ONYX_DIGDEEMPH_CTRL      (1<<4)
+
+#define ONYX_REG_DAC_FILTER            70
+#      define ONYX_ROLLOFF_FAST        (1<<5)
+#      define ONYX_DAC_FILTER_ALWAYS   (1<<2)
+
+#define        ONYX_REG_DAC_OUTPHASE           71
+#      define ONYX_OUTPHASE_INVERTED   (1<<0)
+
+#define ONYX_REG_ADC_CONTROL           72
+#      define ONYX_ADC_INPUT_MIC       (1<<5)
+/* 8 + input gain in dB, valid range for input gain is -4 .. 20 dB */
+#      define ONYX_ADC_PGA_GAIN_MASK   0x1f
+
+#define ONYX_REG_ADC_HPF_BYPASS                75
+#      define ONYX_HPF_DISABLE         (1<<3)
+#      define ONYX_ADC_HPF_ALWAYS      (1<<2)
+
+#define ONYX_REG_DIG_INFO1             77
+#      define ONYX_MASK_DIN_TO_BPZ     (1<<7)
+/* bits 1-5 control channel bits 1-5 */
+#      define ONYX_DIGOUT_DISABLE      (1<<0)
+
+#define ONYX_REG_DIG_INFO2             78
+/* controls channel bits 8-15 */
+
+#define ONYX_REG_DIG_INFO3             79
+/* control channel bits 24-29, high 2 bits reserved */
+
+#define ONYX_REG_DIG_INFO4             80
+#      define ONYX_VALIDL              (1<<7)
+#      define ONYX_VALIDR              (1<<6)
+#      define ONYX_SPDIF_ENABLE        (1<<5)
+/* lower 4 bits control bits 32-35 of channel control and word length */
+#      define ONYX_WORDLEN_MASK        (0xF)
+
+#endif /* __SND_AOA_CODEC_ONYX_H */
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h b/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h
new file mode 100644 (file)
index 0000000..4cfa675
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ This is the program used to generate below table.
+
+#include <stdio.h>
+#include <math.h>
+int main() {
+  int dB2;
+  printf("/" "* This file is only included exactly once!\n");
+  printf(" *\n");
+  printf(" * If they'd only tell us that generating this table was\n");
+  printf(" * as easy as calculating\n");
+  printf(" *      hwvalue = 1048576.0*exp(0.057564628*dB*2)\n");
+  printf(" * :) *" "/\n");
+  printf("static int tas_gaintable[] = {\n");
+  printf("     0x000000, /" "* -infinity dB *" "/\n");
+  for (dB2=-140;dB2<=36;dB2++)
+    printf("   0x%.6x, /" "* %-02.1f dB *" "/\n", (int)(1048576.0*exp(0.057564628*dB2)), dB2/2.0);
+  printf("};\n\n");
+}
+
+*/
+
+/* This file is only included exactly once!
+ *
+ * If they'd only tell us that generating this table was
+ * as easy as calculating
+ *      hwvalue = 1048576.0*exp(0.057564628*dB*2)
+ * :) */
+static int tas_gaintable[] = {
+       0x000000, /* -infinity dB */
+       0x00014b, /* -70.0 dB */
+       0x00015f, /* -69.5 dB */
+       0x000174, /* -69.0 dB */
+       0x00018a, /* -68.5 dB */
+       0x0001a1, /* -68.0 dB */
+       0x0001ba, /* -67.5 dB */
+       0x0001d4, /* -67.0 dB */
+       0x0001f0, /* -66.5 dB */
+       0x00020d, /* -66.0 dB */
+       0x00022c, /* -65.5 dB */
+       0x00024d, /* -65.0 dB */
+       0x000270, /* -64.5 dB */
+       0x000295, /* -64.0 dB */
+       0x0002bc, /* -63.5 dB */
+       0x0002e6, /* -63.0 dB */
+       0x000312, /* -62.5 dB */
+       0x000340, /* -62.0 dB */
+       0x000372, /* -61.5 dB */
+       0x0003a6, /* -61.0 dB */
+       0x0003dd, /* -60.5 dB */
+       0x000418, /* -60.0 dB */
+       0x000456, /* -59.5 dB */
+       0x000498, /* -59.0 dB */
+       0x0004de, /* -58.5 dB */
+       0x000528, /* -58.0 dB */
+       0x000576, /* -57.5 dB */
+       0x0005c9, /* -57.0 dB */
+       0x000620, /* -56.5 dB */
+       0x00067d, /* -56.0 dB */
+       0x0006e0, /* -55.5 dB */
+       0x000748, /* -55.0 dB */
+       0x0007b7, /* -54.5 dB */
+       0x00082c, /* -54.0 dB */
+       0x0008a8, /* -53.5 dB */
+       0x00092b, /* -53.0 dB */
+       0x0009b6, /* -52.5 dB */
+       0x000a49, /* -52.0 dB */
+       0x000ae5, /* -51.5 dB */
+       0x000b8b, /* -51.0 dB */
+       0x000c3a, /* -50.5 dB */
+       0x000cf3, /* -50.0 dB */
+       0x000db8, /* -49.5 dB */
+       0x000e88, /* -49.0 dB */
+       0x000f64, /* -48.5 dB */
+       0x00104e, /* -48.0 dB */
+       0x001145, /* -47.5 dB */
+       0x00124b, /* -47.0 dB */
+       0x001361, /* -46.5 dB */
+       0x001487, /* -46.0 dB */
+       0x0015be, /* -45.5 dB */
+       0x001708, /* -45.0 dB */
+       0x001865, /* -44.5 dB */
+       0x0019d8, /* -44.0 dB */
+       0x001b60, /* -43.5 dB */
+       0x001cff, /* -43.0 dB */
+       0x001eb7, /* -42.5 dB */
+       0x002089, /* -42.0 dB */
+       0x002276, /* -41.5 dB */
+       0x002481, /* -41.0 dB */
+       0x0026ab, /* -40.5 dB */
+       0x0028f5, /* -40.0 dB */
+       0x002b63, /* -39.5 dB */
+       0x002df5, /* -39.0 dB */
+       0x0030ae, /* -38.5 dB */
+       0x003390, /* -38.0 dB */
+       0x00369e, /* -37.5 dB */
+       0x0039db, /* -37.0 dB */
+       0x003d49, /* -36.5 dB */
+       0x0040ea, /* -36.0 dB */
+       0x0044c3, /* -35.5 dB */
+       0x0048d6, /* -35.0 dB */
+       0x004d27, /* -34.5 dB */
+       0x0051b9, /* -34.0 dB */
+       0x005691, /* -33.5 dB */
+       0x005bb2, /* -33.0 dB */
+       0x006121, /* -32.5 dB */
+       0x0066e3, /* -32.0 dB */
+       0x006cfb, /* -31.5 dB */
+       0x007370, /* -31.0 dB */
+       0x007a48, /* -30.5 dB */
+       0x008186, /* -30.0 dB */
+       0x008933, /* -29.5 dB */
+       0x009154, /* -29.0 dB */
+       0x0099f1, /* -28.5 dB */
+       0x00a310, /* -28.0 dB */
+       0x00acba, /* -27.5 dB */
+       0x00b6f6, /* -27.0 dB */
+       0x00c1cd, /* -26.5 dB */
+       0x00cd49, /* -26.0 dB */
+       0x00d973, /* -25.5 dB */
+       0x00e655, /* -25.0 dB */
+       0x00f3fb, /* -24.5 dB */
+       0x010270, /* -24.0 dB */
+       0x0111c0, /* -23.5 dB */
+       0x0121f9, /* -23.0 dB */
+       0x013328, /* -22.5 dB */
+       0x01455b, /* -22.0 dB */
+       0x0158a2, /* -21.5 dB */
+       0x016d0e, /* -21.0 dB */
+       0x0182af, /* -20.5 dB */
+       0x019999, /* -20.0 dB */
+       0x01b1de, /* -19.5 dB */
+       0x01cb94, /* -19.0 dB */
+       0x01e6cf, /* -18.5 dB */
+       0x0203a7, /* -18.0 dB */
+       0x022235, /* -17.5 dB */
+       0x024293, /* -17.0 dB */
+       0x0264db, /* -16.5 dB */
+       0x02892c, /* -16.0 dB */
+       0x02afa3, /* -15.5 dB */
+       0x02d862, /* -15.0 dB */
+       0x03038a, /* -14.5 dB */
+       0x033142, /* -14.0 dB */
+       0x0361af, /* -13.5 dB */
+       0x0394fa, /* -13.0 dB */
+       0x03cb50, /* -12.5 dB */
+       0x0404de, /* -12.0 dB */
+       0x0441d5, /* -11.5 dB */
+       0x048268, /* -11.0 dB */
+       0x04c6d0, /* -10.5 dB */
+       0x050f44, /* -10.0 dB */
+       0x055c04, /* -9.5 dB */
+       0x05ad50, /* -9.0 dB */
+       0x06036e, /* -8.5 dB */
+       0x065ea5, /* -8.0 dB */
+       0x06bf44, /* -7.5 dB */
+       0x07259d, /* -7.0 dB */
+       0x079207, /* -6.5 dB */
+       0x0804dc, /* -6.0 dB */
+       0x087e80, /* -5.5 dB */
+       0x08ff59, /* -5.0 dB */
+       0x0987d5, /* -4.5 dB */
+       0x0a1866, /* -4.0 dB */
+       0x0ab189, /* -3.5 dB */
+       0x0b53be, /* -3.0 dB */
+       0x0bff91, /* -2.5 dB */
+       0x0cb591, /* -2.0 dB */
+       0x0d765a, /* -1.5 dB */
+       0x0e4290, /* -1.0 dB */
+       0x0f1adf, /* -0.5 dB */
+       0x100000, /* 0.0 dB */
+       0x10f2b4, /* 0.5 dB */
+       0x11f3c9, /* 1.0 dB */
+       0x13041a, /* 1.5 dB */
+       0x14248e, /* 2.0 dB */
+       0x15561a, /* 2.5 dB */
+       0x1699c0, /* 3.0 dB */
+       0x17f094, /* 3.5 dB */
+       0x195bb8, /* 4.0 dB */
+       0x1adc61, /* 4.5 dB */
+       0x1c73d5, /* 5.0 dB */
+       0x1e236d, /* 5.5 dB */
+       0x1fec98, /* 6.0 dB */
+       0x21d0d9, /* 6.5 dB */
+       0x23d1cd, /* 7.0 dB */
+       0x25f125, /* 7.5 dB */
+       0x2830af, /* 8.0 dB */
+       0x2a9254, /* 8.5 dB */
+       0x2d1818, /* 9.0 dB */
+       0x2fc420, /* 9.5 dB */
+       0x3298b0, /* 10.0 dB */
+       0x35982f, /* 10.5 dB */
+       0x38c528, /* 11.0 dB */
+       0x3c224c, /* 11.5 dB */
+       0x3fb278, /* 12.0 dB */
+       0x4378b0, /* 12.5 dB */
+       0x477829, /* 13.0 dB */
+       0x4bb446, /* 13.5 dB */
+       0x5030a1, /* 14.0 dB */
+       0x54f106, /* 14.5 dB */
+       0x59f980, /* 15.0 dB */
+       0x5f4e52, /* 15.5 dB */
+       0x64f403, /* 16.0 dB */
+       0x6aef5e, /* 16.5 dB */
+       0x714575, /* 17.0 dB */
+       0x77fbaa, /* 17.5 dB */
+       0x7f17af, /* 18.0 dB */
+};
+
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
new file mode 100644 (file)
index 0000000..2e39ff6
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * Apple Onboard Audio driver for tas codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ * Open questions:
+ *  - How to distinguish between 3004 and versions?
+ *
+ * FIXMEs:
+ *  - This codec driver doesn't honour the 'connected'
+ *    property of the aoa_codec struct, hence if
+ *    it is used in machines where not everything is
+ *    connected it will display wrong mixer elements.
+ *  - Driver assumes that the microphone is always
+ *    monaureal and connected to the right channel of
+ *    the input. This should also be a codec-dependent
+ *    flag, maybe the codec should have 3 different
+ *    bits for the three different possibilities how
+ *    it can be hooked up...
+ *    But as long as I don't see any hardware hooked
+ *    up that way...
+ *  - As Apple notes in their code, the tas3004 seems
+ *    to delay the right channel by one sample. You can
+ *    see this when for example recording stereo in
+ *    audacity, or recording the tas output via cable
+ *    on another machine (use a sinus generator or so).
+ *    I tried programming the BiQuads but couldn't
+ *    make the delay work, maybe someone can read the
+ *    datasheet and fix it. The relevant Apple comment
+ *    is in AppleTAS3004Audio.cpp lines 1637 ff. Note
+ *    that their comment describing how they program
+ *    the filters sucks...
+ *
+ * Other things:
+ *  - this should actually register *two* aoa_codec
+ *    structs since it has two inputs. Then it must
+ *    use the prepare callback to forbid running the
+ *    secondary output on a different clock.
+ *    Also, whatever bus knows how to do this must
+ *    provide two soundbus_dev devices and the fabric
+ *    must be able to link them correctly.
+ *
+ *    I don't even know if Apple ever uses the second
+ *    port on the tas3004 though, I don't think their
+ *    i2s controllers can even do it. OTOH, they all
+ *    derive the clocks from common clocks, so it
+ *    might just be possible. The framework allows the
+ *    codec to refine the transfer_info items in the
+ *    usable callback, so we can simply remove the
+ *    rates the second instance is not using when it
+ *    actually is in use.
+ *    Maybe we'll need to make the sound busses have
+ *    a 'clock group id' value so the codec can
+ *    determine if the two outputs can be driven at
+ *    the same time. But that is likely overkill, up
+ *    to the fabric to not link them up incorrectly,
+ *    and up to the hardware designer to not wire
+ *    them up in some weird unusable way.
+ */
+#include <stddef.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <asm/pmac_low_i2c.h>
+#include <asm/prom.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("tas codec driver for snd-aoa");
+
+#include "snd-aoa-codec-tas.h"
+#include "snd-aoa-codec-tas-gain-table.h"
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+
+#define PFX "snd-aoa-codec-tas: "
+
+struct tas {
+       struct aoa_codec        codec;
+       struct i2c_client       i2c;
+       u32                     muted_l:1, muted_r:1,
+                               controls_created:1;
+       u8                      cached_volume_l, cached_volume_r;
+       u8                      mixer_l[3], mixer_r[3];
+       u8                      acr;
+};
+
+static struct tas *codec_to_tas(struct aoa_codec *codec)
+{
+       return container_of(codec, struct tas, codec);
+}
+
+static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data)
+{
+       if (len == 1)
+               return i2c_smbus_write_byte_data(&tas->i2c, reg, *data);
+       else
+               return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data);
+}
+
+static void tas_set_volume(struct tas *tas)
+{
+       u8 block[6];
+       int tmp;
+       u8 left, right;
+
+       left = tas->cached_volume_l;
+       right = tas->cached_volume_r;
+
+       if (left > 177) left = 177;
+       if (right > 177) right = 177;
+
+       if (tas->muted_l) left = 0;
+       if (tas->muted_r) right = 0;
+
+       /* analysing the volume and mixer tables shows
+        * that they are similar enough when we shift
+        * the mixer table down by 4 bits. The error
+        * is miniscule, in just one item the error
+        * is 1, at a value of 0x07f17b (mixer table
+        * value is 0x07f17a) */
+       tmp = tas_gaintable[left];
+       block[0] = tmp>>20;
+       block[1] = tmp>>12;
+       block[2] = tmp>>4;
+       tmp = tas_gaintable[right];
+       block[3] = tmp>>20;
+       block[4] = tmp>>12;
+       block[5] = tmp>>4;
+       tas_write_reg(tas, TAS_REG_VOL, 6, block);
+}
+
+static void tas_set_mixer(struct tas *tas)
+{
+       u8 block[9];
+       int tmp, i;
+       u8 val;
+
+       for (i=0;i<3;i++) {
+               val = tas->mixer_l[i];
+               if (val > 177) val = 177;
+               tmp = tas_gaintable[val];
+               block[3*i+0] = tmp>>16;
+               block[3*i+1] = tmp>>8;
+               block[3*i+2] = tmp;
+       }
+       tas_write_reg(tas, TAS_REG_LMIX, 9, block);
+
+       for (i=0;i<3;i++) {
+               val = tas->mixer_r[i];
+               if (val > 177) val = 177;
+               tmp = tas_gaintable[val];
+               block[3*i+0] = tmp>>16;
+               block[3*i+1] = tmp>>8;
+               block[3*i+2] = tmp;
+       }
+       tas_write_reg(tas, TAS_REG_RMIX, 9, block);
+}
+
+/* alsa stuff */
+
+static int tas_dev_register(struct snd_device *dev)
+{
+       return 0;
+}
+
+static struct snd_device_ops ops = {
+       .dev_register = tas_dev_register,
+};
+
+static int tas_snd_vol_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 177;
+       return 0;
+}
+
+static int tas_snd_vol_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = tas->cached_volume_l;
+       ucontrol->value.integer.value[1] = tas->cached_volume_r;
+       return 0;
+}
+
+static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+       if (tas->cached_volume_l == ucontrol->value.integer.value[0]
+        && tas->cached_volume_r == ucontrol->value.integer.value[1])
+               return 0;
+
+       tas->cached_volume_l = ucontrol->value.integer.value[0];
+       tas->cached_volume_r = ucontrol->value.integer.value[1];
+       tas_set_volume(tas);
+       return 1;
+}
+
+static struct snd_kcontrol_new volume_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Master Playback Volume",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = tas_snd_vol_info,
+       .get = tas_snd_vol_get,
+       .put = tas_snd_vol_put,
+};
+
+static int tas_snd_mute_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = !tas->muted_l;
+       ucontrol->value.integer.value[1] = !tas->muted_r;
+       return 0;
+}
+
+static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+       if (tas->muted_l == !ucontrol->value.integer.value[0]
+        && tas->muted_r == !ucontrol->value.integer.value[1])
+               return 0;
+
+       tas->muted_l = !ucontrol->value.integer.value[0];
+       tas->muted_r = !ucontrol->value.integer.value[1];
+       tas_set_volume(tas);
+       return 1;
+}
+
+static struct snd_kcontrol_new mute_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Master Playback Switch",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = tas_snd_mute_info,
+       .get = tas_snd_mute_get,
+       .put = tas_snd_mute_put,
+};
+
+static int tas_snd_mixer_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 177;
+       return 0;
+}
+
+static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+       int idx = kcontrol->private_value;
+
+       ucontrol->value.integer.value[0] = tas->mixer_l[idx];
+       ucontrol->value.integer.value[1] = tas->mixer_r[idx];
+
+       return 0;
+}
+
+static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+       int idx = kcontrol->private_value;
+
+       if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
+        && tas->mixer_r[idx] == ucontrol->value.integer.value[1])
+               return 0;
+
+       tas->mixer_l[idx] = ucontrol->value.integer.value[0];
+       tas->mixer_r[idx] = ucontrol->value.integer.value[1];
+
+       tas_set_mixer(tas);
+       return 1;
+}
+
+#define MIXER_CONTROL(n,descr,idx)                     \
+static struct snd_kcontrol_new n##_control = {         \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
+       .name = descr " Playback Volume",               \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,      \
+       .info = tas_snd_mixer_info,                     \
+       .get = tas_snd_mixer_get,                       \
+       .put = tas_snd_mixer_put,                       \
+       .private_value = idx,                           \
+}
+
+MIXER_CONTROL(pcm1, "PCM1", 0);
+MIXER_CONTROL(monitor, "Monitor", 2);
+
+static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = { "Line-In", "Microphone" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item > 1)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
+       return 0;
+}
+
+static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tas *tas = snd_kcontrol_chip(kcontrol);
+       int oldacr = tas->acr;
+
+       tas->acr &= ~TAS_ACR_INPUT_B;
+       if (ucontrol->value.enumerated.item[0])
+               tas->acr |= TAS_ACR_INPUT_B;
+       if (oldacr == tas->acr)
+               return 0;
+       tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+       return 1;
+}
+
+static struct snd_kcontrol_new capture_source_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       /* If we name this 'Input Source', it properly shows up in
+        * alsamixer as a selection, * but it's shown under the
+        * 'Playback' category.
+        * If I name it 'Capture Source', it shows up in strange
+        * ways (two bools of which one can be selected at a
+        * time) but at least it's shown in the 'Capture'
+        * category.
+        * I was told that this was due to backward compatibility,
+        * but I don't understand then why the mangling is *not*
+        * done when I name it "Input Source".....
+        */
+       .name = "Capture Source",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = tas_snd_capture_source_info,
+       .get = tas_snd_capture_source_get,
+       .put = tas_snd_capture_source_put,
+};
+
+
+static struct transfer_info tas_transfers[] = {
+       {
+               /* input */
+               .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
+                          SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+               .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+               .transfer_in = 1,
+       },
+       {
+               /* output */
+               .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
+                          SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+               .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+               .transfer_in = 0,
+       },
+       {}
+};
+
+static int tas_usable(struct codec_info_item *cii,
+                     struct transfer_info *ti,
+                     struct transfer_info *out)
+{
+       return 1;
+}
+
+static int tas_reset_init(struct tas *tas)
+{
+       u8 tmp;
+       tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
+       msleep(1);
+       tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1);
+       msleep(1);
+       tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
+       msleep(1);
+
+       tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
+       tas->acr |= TAS_ACR_B_MONAUREAL | TAS_ACR_B_MON_SEL_RIGHT;
+       if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+               return -ENODEV;
+
+       tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
+       if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
+               return -ENODEV;
+
+       tmp = 0;
+       if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
+               return -ENODEV;
+
+       return 0;
+}
+
+/* we are controlled via i2c and assume that is always up
+ * If that wasn't the case, we'd have to suspend once
+ * our i2c device is suspended, and then take note of that! */
+static int tas_suspend(struct tas *tas)
+{
+       tas->acr |= TAS_ACR_ANALOG_PDOWN;
+       tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+       return 0;
+}
+
+static int tas_resume(struct tas *tas)
+{
+       /* reset codec */
+       tas_reset_init(tas);
+       tas_set_volume(tas);
+       tas_set_mixer(tas);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int _tas_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+       return tas_suspend(cii->codec_data);
+}
+
+static int _tas_resume(struct codec_info_item *cii)
+{
+       return tas_resume(cii->codec_data);
+}
+#endif
+
+static struct codec_info tas_codec_info = {
+       .transfers = tas_transfers,
+       /* in theory, we can drive it at 512 too...
+        * but so far the framework doesn't allow
+        * for that and I don't see much point in it. */
+       .sysclock_factor = 256,
+       /* same here, could be 32 for just one 16 bit format */
+       .bus_factor = 64,
+       .owner = THIS_MODULE,
+       .usable = tas_usable,
+#ifdef CONFIG_PM
+       .suspend = _tas_suspend,
+       .resume = _tas_resume,
+#endif
+};
+
+static int tas_init_codec(struct aoa_codec *codec)
+{
+       struct tas *tas = codec_to_tas(codec);
+       int err;
+
+       if (!tas->codec.gpio || !tas->codec.gpio->methods) {
+               printk(KERN_ERR PFX "gpios not assigned!!\n");
+               return -EINVAL;
+       }
+
+       if (tas_reset_init(tas)) {
+               printk(KERN_ERR PFX "tas failed to initialise\n");
+               return -ENXIO;
+       }
+
+       if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
+                                                  aoa_get_card(),
+                                                  &tas_codec_info, tas)) {
+               printk(KERN_ERR PFX "error attaching tas to soundbus\n");
+               return -ENODEV;
+       }
+
+       if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, tas, &ops)) {
+               printk(KERN_ERR PFX "failed to create tas snd device!\n");
+               return -ENODEV;
+       }
+       err = aoa_snd_ctl_add(snd_ctl_new1(&volume_control, tas));
+       if (err)
+               goto error;
+
+       err = aoa_snd_ctl_add(snd_ctl_new1(&mute_control, tas));
+       if (err)
+               goto error;
+
+       err = aoa_snd_ctl_add(snd_ctl_new1(&pcm1_control, tas));
+       if (err)
+               goto error;
+
+       err = aoa_snd_ctl_add(snd_ctl_new1(&monitor_control, tas));
+       if (err)
+               goto error;
+
+       err = aoa_snd_ctl_add(snd_ctl_new1(&capture_source_control, tas));
+       if (err)
+               goto error;
+
+       return 0;
+ error:
+       tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
+       snd_device_free(aoa_get_card(), tas);
+       return err;
+}
+
+static void tas_exit_codec(struct aoa_codec *codec)
+{
+       struct tas *tas = codec_to_tas(codec);
+
+       if (!tas->codec.soundbus_dev)
+               return;
+       tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
+}
+       
+
+static struct i2c_driver tas_driver;
+
+static int tas_create(struct i2c_adapter *adapter,
+                      struct device_node *node,
+                      int addr)
+{
+       struct tas *tas;
+
+       tas = kzalloc(sizeof(struct tas), GFP_KERNEL);
+
+       if (!tas)
+               return -ENOMEM;
+
+       tas->i2c.driver = &tas_driver;
+       tas->i2c.adapter = adapter;
+       tas->i2c.addr = addr;
+       strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1);
+
+       if (i2c_attach_client(&tas->i2c)) {
+               printk(KERN_ERR PFX "failed to attach to i2c\n");
+               goto fail;
+       }
+
+       strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN-1);
+       tas->codec.owner = THIS_MODULE;
+       tas->codec.init = tas_init_codec;
+       tas->codec.exit = tas_exit_codec;
+       tas->codec.node = of_node_get(node);
+
+       if (aoa_codec_register(&tas->codec)) {
+               goto detach;
+       }
+       printk(KERN_DEBUG "snd-aoa-codec-tas: created and attached tas instance\n");
+       return 0;
+ detach:
+       i2c_detach_client(&tas->i2c);
+ fail:
+       kfree(tas);
+       return -EINVAL;
+}
+
+static int tas_i2c_attach(struct i2c_adapter *adapter)
+{
+       struct device_node *busnode, *dev = NULL;
+       struct pmac_i2c_bus *bus;
+
+       bus = pmac_i2c_adapter_to_bus(adapter);
+       if (bus == NULL)
+               return -ENODEV;
+       busnode = pmac_i2c_get_bus_node(bus);
+
+       while ((dev = of_get_next_child(busnode, dev)) != NULL) {
+               if (device_is_compatible(dev, "tas3004")) {
+                       u32 *addr;
+                       printk(KERN_DEBUG PFX "found tas3004\n");
+                       addr = (u32 *) get_property(dev, "reg", NULL);
+                       if (!addr)
+                               continue;
+                       return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
+               }
+               /* older machines have no 'codec' node with a 'compatible'
+                * property that says 'tas3004', they just have a 'deq'
+                * node without any such property... */
+               if (strcmp(dev->name, "deq") == 0) {
+                       u32 *_addr, addr;
+                       printk(KERN_DEBUG PFX "found 'deq' node\n");
+                       _addr = (u32 *) get_property(dev, "i2c-address", NULL);
+                       if (!_addr)
+                               continue;
+                       addr = ((*_addr) >> 1) & 0x7f;
+                       /* now, if the address doesn't match any of the two
+                        * that a tas3004 can have, we cannot handle this.
+                        * I doubt it ever happens but hey. */
+                       if (addr != 0x34 && addr != 0x35)
+                               continue;
+                       return tas_create(adapter, dev, addr);
+               }
+       }
+       return -ENODEV;
+}
+
+static int tas_i2c_detach(struct i2c_client *client)
+{
+       struct tas *tas = container_of(client, struct tas, i2c);
+       int err;
+       u8 tmp = TAS_ACR_ANALOG_PDOWN;
+
+       if ((err = i2c_detach_client(client)))
+               return err;
+       aoa_codec_unregister(&tas->codec);
+       of_node_put(tas->codec.node);
+
+       /* power down codec chip */
+       tas_write_reg(tas, TAS_REG_ACR, 1, &tmp);
+
+       kfree(tas);
+       return 0;
+}
+
+static struct i2c_driver tas_driver = {
+       .driver = {
+               .name = "aoa_codec_tas",
+               .owner = THIS_MODULE,
+       },
+       .attach_adapter = tas_i2c_attach,
+       .detach_client = tas_i2c_detach,
+};
+
+static int __init tas_init(void)
+{
+       return i2c_add_driver(&tas_driver);
+}
+
+static void __exit tas_exit(void)
+{
+       i2c_del_driver(&tas_driver);
+}
+
+module_init(tas_init);
+module_exit(tas_exit);
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/snd-aoa-codec-tas.h
new file mode 100644 (file)
index 0000000..daf81f4
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Apple Onboard Audio driver for tas codec (header)
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __SND_AOA_CODECTASH
+#define __SND_AOA_CODECTASH
+
+#define TAS_REG_MCS    0x01    /* main control */
+#      define TAS_MCS_FASTLOAD         (1<<7)
+#      define TAS_MCS_SCLK64           (1<<6)
+#      define TAS_MCS_SPORT_MODE_MASK  (3<<4)
+#      define TAS_MCS_SPORT_MODE_I2S   (2<<4)
+#      define TAS_MCS_SPORT_MODE_RJ    (1<<4)
+#      define TAS_MCS_SPORT_MODE_LJ    (0<<4)
+#      define TAS_MCS_SPORT_WL_MASK    (3<<0)
+#      define TAS_MCS_SPORT_WL_16BIT   (0<<0)
+#      define TAS_MCS_SPORT_WL_18BIT   (1<<0)
+#      define TAS_MCS_SPORT_WL_20BIT   (2<<0)
+#      define TAS_MCS_SPORT_WL_24BIT   (3<<0)
+
+#define TAS_REG_DRC    0x02
+#define TAS_REG_VOL    0x04
+#define TAS_REG_TREBLE 0x05
+#define TAS_REG_BASS   0x06
+#define TAS_REG_LMIX   0x07
+#define TAS_REG_RMIX   0x08
+
+#define TAS_REG_ACR    0x40    /* analog control */
+#      define TAS_ACR_B_MONAUREAL      (1<<7)
+#      define TAS_ACR_B_MON_SEL_RIGHT  (1<<6)
+#      define TAS_ACR_DEEMPH_MASK      (3<<2)
+#      define TAS_ACR_DEEMPH_OFF       (0<<2)
+#      define TAS_ACR_DEEMPH_48KHz     (1<<2)
+#      define TAS_ACR_DEEMPH_44KHz     (2<<2)
+#      define TAS_ACR_INPUT_B          (1<<1)
+#      define TAS_ACR_ANALOG_PDOWN     (1<<0)
+
+#define TAS_REG_MCS2   0x43    /* main control 2 */
+#      define TAS_MCS2_ALLPASS         (1<<1)
+
+#define TAS_REG_LEFT_BIQUAD6   0x10
+#define TAS_REG_RIGHT_BIQUAD6  0x19
+
+#endif /* __SND_AOA_CODECTASH */
diff --git a/sound/aoa/codecs/snd-aoa-codec-toonie.c b/sound/aoa/codecs/snd-aoa-codec-toonie.c
new file mode 100644 (file)
index 0000000..bcc5556
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Apple Onboard Audio driver for Toonie codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This is a driver for the toonie codec chip. This chip is present
+ * on the Mac Mini and is nothing but a DAC.
+ */
+#include <linux/delay.h>
+#include <linux/module.h>
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("toonie codec driver for snd-aoa");
+
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+
+#define PFX "snd-aoa-codec-toonie: "
+
+struct toonie {
+       struct aoa_codec        codec;
+};
+#define codec_to_toonie(c) container_of(c, struct toonie, codec)
+
+static int toonie_dev_register(struct snd_device *dev)
+{
+       return 0;
+}
+
+static struct snd_device_ops ops = {
+       .dev_register = toonie_dev_register,
+};
+
+static struct transfer_info toonie_transfers[] = {
+       /* This thing *only* has analog output,
+        * the rates are taken from Info.plist
+        * from Darwin. */
+       {
+               .formats = SNDRV_PCM_FMTBIT_S16_BE |
+                          SNDRV_PCM_FMTBIT_S24_BE,
+               .rates = SNDRV_PCM_RATE_32000 |
+                        SNDRV_PCM_RATE_44100 |
+                        SNDRV_PCM_RATE_48000 |
+                        SNDRV_PCM_RATE_88200 |
+                        SNDRV_PCM_RATE_96000,
+       },
+       {}
+};
+
+#ifdef CONFIG_PM
+static int toonie_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+       /* can we turn it off somehow? */
+       return 0;
+}
+
+static int toonie_resume(struct codec_info_item *cii)
+{
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct codec_info toonie_codec_info = {
+       .transfers = toonie_transfers,
+       .sysclock_factor = 256,
+       .bus_factor = 64,
+       .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+       .suspend = toonie_suspend,
+       .resume = toonie_resume,
+#endif
+};
+
+static int toonie_init_codec(struct aoa_codec *codec)
+{
+       struct toonie *toonie = codec_to_toonie(codec);
+
+       if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, toonie, &ops)) {
+               printk(KERN_ERR PFX "failed to create toonie snd device!\n");
+               return -ENODEV;
+       }
+
+       /* nothing connected? what a joke! */
+       if (toonie->codec.connected != 1)
+               return -ENOTCONN;
+
+       if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev,
+                                                    aoa_get_card(),
+                                                    &toonie_codec_info, toonie)) {
+               printk(KERN_ERR PFX "error creating toonie pcm\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void toonie_exit_codec(struct aoa_codec *codec)
+{
+       struct toonie *toonie = codec_to_toonie(codec);
+
+       if (!toonie->codec.soundbus_dev) {
+               printk(KERN_ERR PFX "toonie_exit_codec called without soundbus_dev!\n");
+               return;
+       }
+       toonie->codec.soundbus_dev->detach_codec(toonie->codec.soundbus_dev, toonie);
+}
+
+static struct toonie *toonie;
+
+static int __init toonie_init(void)
+{
+       toonie = kzalloc(sizeof(struct toonie), GFP_KERNEL);
+
+       if (!toonie)
+               return -ENOMEM;
+
+       strlcpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name));
+       toonie->codec.owner = THIS_MODULE;
+       toonie->codec.init = toonie_init_codec;
+       toonie->codec.exit = toonie_exit_codec;
+                                        
+       if (aoa_codec_register(&toonie->codec)) {
+               kfree(toonie);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void __exit toonie_exit(void)
+{
+       aoa_codec_unregister(&toonie->codec);
+       kfree(toonie);
+}
+
+module_init(toonie_init);
+module_exit(toonie_exit);
diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile
new file mode 100644 (file)
index 0000000..62dc728
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_SND_AOA) += snd-aoa.o
+snd-aoa-objs := snd-aoa-core.o \
+               snd-aoa-alsa.o \
+               snd-aoa-gpio-pmf.o \
+               snd-aoa-gpio-feature.o
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c
new file mode 100644 (file)
index 0000000..b42fdea
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Apple Onboard Audio Alsa helpers
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#include <linux/module.h>
+#include "snd-aoa-alsa.h"
+
+static int index = -1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "index for AOA sound card.");
+
+static struct aoa_card *aoa_card;
+
+int aoa_alsa_init(char *name, struct module *mod)
+{
+       struct snd_card *alsa_card;
+       int err;
+
+       if (aoa_card)
+               /* cannot be EEXIST due to usage in aoa_fabric_register */
+               return -EBUSY;
+
+       alsa_card = snd_card_new(index, name, mod, sizeof(struct aoa_card));
+       if (!alsa_card)
+               return -ENOMEM;
+       aoa_card = alsa_card->private_data;
+       aoa_card->alsa_card = alsa_card;
+       strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver));
+       strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname));
+       strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname));
+       strlcpy(alsa_card->mixername, name, sizeof(alsa_card->mixername));
+       err = snd_card_register(aoa_card->alsa_card);
+       if (err < 0) {
+               printk(KERN_ERR "snd-aoa: couldn't register alsa card\n");
+               snd_card_free(aoa_card->alsa_card);
+               aoa_card = NULL;
+               return err;
+       }
+       return 0;
+}
+
+struct snd_card *aoa_get_card(void)
+{
+       if (aoa_card)
+               return aoa_card->alsa_card;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(aoa_get_card);
+
+void aoa_alsa_cleanup(void)
+{
+       if (aoa_card) {
+               snd_card_free(aoa_card->alsa_card);
+               aoa_card = NULL;
+       }
+}
+
+int aoa_snd_device_new(snd_device_type_t type,
+        void * device_data, struct snd_device_ops * ops)
+{
+       struct snd_card *card = aoa_get_card();
+       int err;
+       
+       if (!card) return -ENOMEM;
+
+       err = snd_device_new(card, type, device_data, ops);
+       if (err) {
+               printk(KERN_ERR "snd-aoa: failed to create snd device (%d)\n", err);
+               return err;
+       }
+       err = snd_device_register(card, device_data);
+       if (err) {
+               printk(KERN_ERR "snd-aoa: failed to register "
+                               "snd device (%d)\n", err);
+               printk(KERN_ERR "snd-aoa: have you forgotten the "
+                               "dev_register callback?\n");
+               snd_device_free(card, device_data);
+       }
+       return err;
+}
+EXPORT_SYMBOL_GPL(aoa_snd_device_new);
+
+int aoa_snd_ctl_add(struct snd_kcontrol* control)
+{
+       int err;
+
+       if (!aoa_card) return -ENODEV;
+
+       err = snd_ctl_add(aoa_card->alsa_card, control);
+       if (err)
+               printk(KERN_ERR "snd-aoa: failed to add alsa control (%d)\n",
+                      err);
+       return err;
+}
+EXPORT_SYMBOL_GPL(aoa_snd_ctl_add);
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h
new file mode 100644 (file)
index 0000000..660d2f1
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Apple Onboard Audio Alsa private helpers
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#ifndef __SND_AOA_ALSA_H
+#define __SND_AOA_ALSA_H
+#include "../aoa.h"
+
+extern int aoa_alsa_init(char *name, struct module *mod);
+extern void aoa_alsa_cleanup(void);
+
+#endif /* __SND_AOA_ALSA_H */
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c
new file mode 100644 (file)
index 0000000..ecd2d82
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Apple Onboard Audio driver core
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include "../aoa.h"
+#include "snd-aoa-alsa.h"
+
+MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+
+/* We allow only one fabric. This simplifies things,
+ * and more don't really make that much sense */
+static struct aoa_fabric *fabric;
+static LIST_HEAD(codec_list);
+
+static int attach_codec_to_fabric(struct aoa_codec *c)
+{
+       int err;
+
+       if (!try_module_get(c->owner))
+               return -EBUSY;
+       /* found_codec has to be assigned */
+       err = -ENOENT;
+       if (fabric->found_codec)
+               err = fabric->found_codec(c);
+       if (err) {
+               module_put(c->owner);
+               printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n",
+                               c->name);
+               return err;
+       }
+       c->fabric = fabric;
+
+       err = 0;
+       if (c->init)
+               err = c->init(c);
+       if (err) {
+               printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name);
+               c->fabric = NULL;
+               if (fabric->remove_codec)
+                       fabric->remove_codec(c);
+               module_put(c->owner);
+               return err;
+       }
+       if (fabric->attached_codec)
+               fabric->attached_codec(c);
+       return 0;
+}
+
+int aoa_codec_register(struct aoa_codec *codec)
+{
+       int err = 0;
+
+       /* if there's a fabric already, we can tell if we
+        * will want to have this codec, so propagate error
+        * through. Otherwise, this will happen later... */
+       if (fabric)
+               err = attach_codec_to_fabric(codec);
+       if (!err)
+               list_add(&codec->list, &codec_list);
+       return err;
+}
+EXPORT_SYMBOL_GPL(aoa_codec_register);
+
+void aoa_codec_unregister(struct aoa_codec *codec)
+{
+       list_del(&codec->list);
+       if (codec->fabric && codec->exit)
+               codec->exit(codec);
+       if (fabric && fabric->remove_codec)
+               fabric->remove_codec(codec);
+       codec->fabric = NULL;
+       module_put(codec->owner);
+}
+EXPORT_SYMBOL_GPL(aoa_codec_unregister);
+
+int aoa_fabric_register(struct aoa_fabric *new_fabric)
+{
+       struct aoa_codec *c;
+       int err;
+
+       /* allow querying for presence of fabric
+        * (i.e. do this test first!) */
+       if (new_fabric == fabric) {
+               err = -EALREADY;
+               goto attach;
+       }
+       if (fabric)
+               return -EEXIST;
+       if (!new_fabric)
+               return -EINVAL;
+
+       err = aoa_alsa_init(new_fabric->name, new_fabric->owner);
+       if (err)
+               return err;
+
+       fabric = new_fabric;
+
+ attach:
+       list_for_each_entry(c, &codec_list, list) {
+               if (c->fabric != fabric)
+                       attach_codec_to_fabric(c);
+       }
+       return err;
+}
+EXPORT_SYMBOL_GPL(aoa_fabric_register);
+
+void aoa_fabric_unregister(struct aoa_fabric *old_fabric)
+{
+       struct aoa_codec *c;
+
+       if (fabric != old_fabric)
+               return;
+
+       list_for_each_entry(c, &codec_list, list) {
+               if (c->fabric)
+                       aoa_fabric_unlink_codec(c);
+       }
+
+       aoa_alsa_cleanup();
+
+       fabric = NULL;
+}
+EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
+
+void aoa_fabric_unlink_codec(struct aoa_codec *codec)
+{
+       if (!codec->fabric) {
+               printk(KERN_ERR "snd-aoa: fabric unassigned "
+                               "in aoa_fabric_unlink_codec\n");
+               dump_stack();
+               return;
+       }
+       if (codec->exit)
+               codec->exit(codec);
+       if (codec->fabric->remove_codec)
+               codec->fabric->remove_codec(codec);
+       codec->fabric = NULL;
+       module_put(codec->owner);
+}
+EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
+
+static int __init aoa_init(void)
+{
+       return 0;
+}
+
+static void __exit aoa_exit(void)
+{
+       aoa_alsa_cleanup();
+}
+
+module_init(aoa_init);
+module_exit(aoa_exit);
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c
new file mode 100644 (file)
index 0000000..2c6eb77
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Apple Onboard Audio feature call GPIO control
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ * This file contains the GPIO control routines for 
+ * direct (through feature calls) access to the GPIO
+ * registers.
+ */
+
+#include <asm/pmac_feature.h>
+#include <linux/interrupt.h>
+#include "../aoa.h"
+
+/* TODO: these are 20 global variables
+ * that aren't used on most machines...
+ * Move them into a dynamically allocated
+ * structure and use that.
+ */
+
+/* these are the GPIO numbers (register addresses as offsets into
+ * the GPIO space) */
+static int headphone_mute_gpio;
+static int amp_mute_gpio;
+static int lineout_mute_gpio;
+static int hw_reset_gpio;
+static int lineout_detect_gpio;
+static int headphone_detect_gpio;
+static int linein_detect_gpio;
+
+/* see the SWITCH_GPIO macro */
+static int headphone_mute_gpio_activestate;
+static int amp_mute_gpio_activestate;
+static int lineout_mute_gpio_activestate;
+static int hw_reset_gpio_activestate;
+static int lineout_detect_gpio_activestate;
+static int headphone_detect_gpio_activestate;
+static int linein_detect_gpio_activestate;
+
+/* node pointers that we save when getting the GPIO number
+ * to get the interrupt later */
+static struct device_node *lineout_detect_node;
+static struct device_node *linein_detect_node;
+static struct device_node *headphone_detect_node;
+
+static int lineout_detect_irq;
+static int linein_detect_irq;
+static int headphone_detect_irq;
+
+static struct device_node *get_gpio(char *name,
+                                   char *altname,
+                                   int *gpioptr,
+                                   int *gpioactiveptr)
+{
+       struct device_node *np, *gpio;
+       u32 *reg;
+       char *audio_gpio;
+
+       *gpioptr = -1;
+
+       /* check if we can get it the easy way ... */
+       np = of_find_node_by_name(NULL, name);
+       if (!np) {
+               /* some machines have only gpioX/extint-gpioX nodes,
+                * and an audio-gpio property saying what it is ...
+                * So what we have to do is enumerate all children
+                * of the gpio node and check them all. */
+               gpio = of_find_node_by_name(NULL, "gpio");
+               if (!gpio)
+                       return NULL;
+               while ((np = of_get_next_child(gpio, np))) {
+                       audio_gpio = get_property(np, "audio-gpio", NULL);
+                       if (!audio_gpio)
+                               continue;
+                       if (strcmp(audio_gpio, name) == 0)
+                               break;
+                       if (altname && (strcmp(audio_gpio, altname) == 0))
+                               break;
+               }
+               /* still not found, assume not there */
+               if (!np)
+                       return NULL;
+       }
+
+       reg = (u32 *)get_property(np, "reg", NULL);
+       if (!reg)
+               return NULL;
+
+       *gpioptr = *reg;
+
+       /* this is a hack, usually the GPIOs 'reg' property
+        * should have the offset based from the GPIO space
+        * which is at 0x50, but apparently not always... */
+       if (*gpioptr < 0x50)
+               *gpioptr += 0x50;
+
+       reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+       if (!reg)
+               /* Apple seems to default to 1, but
+                * that doesn't seem right at least on most
+                * machines. So until proven that the opposite
+                * is necessary, we default to 0
+                * (which, incidentally, snd-powermac also does...) */
+               *gpioactiveptr = 0;
+       else
+               *gpioactiveptr = *reg;
+
+       return np;
+}
+
+static void get_irq(struct device_node * np, int *irqptr)
+{
+       *irqptr = -1;
+       if (!np)
+               return;
+       if (np->n_intrs != 1)
+               return;
+       *irqptr = np->intrs[0].line;
+}
+
+/* 0x4 is outenable, 0x1 is out, thus 4 or 5 */
+#define SWITCH_GPIO(name, v, on)                               \
+       (((v)&~1) | ((on)?                                      \
+                       (name##_gpio_activestate==0?4:5):       \
+                       (name##_gpio_activestate==0?5:4)))
+
+#define FTR_GPIO(name, bit)                                    \
+static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\
+{                                                              \
+       int v;                                                  \
+                                                               \
+       if (unlikely(!rt)) return;                              \
+                                                               \
+       if (name##_mute_gpio < 0)                               \
+               return;                                         \
+                                                               \
+       v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,         \
+                             name##_mute_gpio,                 \
+                             0);                               \
+                                                               \
+       /* muted = !on... */                                    \
+       v = SWITCH_GPIO(name##_mute, v, !on);                   \
+                                                               \
+       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,            \
+                         name##_mute_gpio, v);                 \
+                                                               \
+       rt->implementation_private &= ~(1<<bit);                \
+       rt->implementation_private |= (!!on << bit);            \
+}                                                              \
+static int ftr_gpio_get_##name(struct gpio_runtime *rt)                \
+{                                                              \
+       if (unlikely(!rt)) return 0;                            \
+       return (rt->implementation_private>>bit)&1;             \
+}
+
+FTR_GPIO(headphone, 0);
+FTR_GPIO(amp, 1);
+FTR_GPIO(lineout, 2);
+
+static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
+{
+       int v;
+
+       if (unlikely(!rt)) return;
+       if (hw_reset_gpio < 0)
+               return;
+
+       v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL,
+                             hw_reset_gpio, 0);
+       v = SWITCH_GPIO(hw_reset, v, on);
+       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
+                         hw_reset_gpio, v);
+}
+
+static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
+{
+       int saved;
+
+       if (unlikely(!rt)) return;
+       saved = rt->implementation_private;
+       ftr_gpio_set_headphone(rt, 0);
+       ftr_gpio_set_amp(rt, 0);
+       ftr_gpio_set_lineout(rt, 0);
+       rt->implementation_private = saved;
+}
+
+static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
+{
+       int s;
+
+       if (unlikely(!rt)) return;
+       s = rt->implementation_private;
+       ftr_gpio_set_headphone(rt, (s>>0)&1);
+       ftr_gpio_set_amp(rt, (s>>1)&1);
+       ftr_gpio_set_lineout(rt, (s>>2)&1);
+}
+
+static void ftr_handle_notify(void *data)
+{
+       struct gpio_notification *notif = data;
+
+       mutex_lock(&notif->mutex);
+       if (notif->notify)
+               notif->notify(notif->data);
+       mutex_unlock(&notif->mutex);
+}
+
+static void ftr_gpio_init(struct gpio_runtime *rt)
+{
+       get_gpio("headphone-mute", NULL,
+                &headphone_mute_gpio,
+                &headphone_mute_gpio_activestate);
+       get_gpio("amp-mute", NULL,
+                &amp_mute_gpio,
+                &amp_mute_gpio_activestate);
+       get_gpio("lineout-mute", NULL,
+                &lineout_mute_gpio,
+                &lineout_mute_gpio_activestate);
+       get_gpio("hw-reset", "audio-hw-reset",
+                &hw_reset_gpio,
+                &hw_reset_gpio_activestate);
+
+       headphone_detect_node = get_gpio("headphone-detect", NULL,
+                                        &headphone_detect_gpio,
+                                        &headphone_detect_gpio_activestate);
+       /* go Apple, and thanks for giving these different names
+        * across the board... */
+       lineout_detect_node = get_gpio("lineout-detect", "line-output-detect",
+                                      &lineout_detect_gpio,
+                                      &lineout_detect_gpio_activestate);
+       linein_detect_node = get_gpio("linein-detect", "line-input-detect",
+                                     &linein_detect_gpio,
+                                     &linein_detect_gpio_activestate);
+
+       get_irq(headphone_detect_node, &headphone_detect_irq);
+       get_irq(lineout_detect_node, &lineout_detect_irq);
+       get_irq(linein_detect_node, &linein_detect_irq);
+
+       ftr_gpio_all_amps_off(rt);
+       rt->implementation_private = 0;
+       INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify,
+                 &rt->headphone_notify);
+       INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify,
+                 &rt->line_in_notify);
+       INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify,
+                 &rt->line_out_notify);
+       mutex_init(&rt->headphone_notify.mutex);
+       mutex_init(&rt->line_in_notify.mutex);
+       mutex_init(&rt->line_out_notify.mutex);
+}
+
+static void ftr_gpio_exit(struct gpio_runtime *rt)
+{
+       ftr_gpio_all_amps_off(rt);
+       rt->implementation_private = 0;
+       if (rt->headphone_notify.notify)
+               free_irq(headphone_detect_irq, &rt->headphone_notify);
+       if (rt->line_in_notify.gpio_private)
+               free_irq(linein_detect_irq, &rt->line_in_notify);
+       if (rt->line_out_notify.gpio_private)
+               free_irq(lineout_detect_irq, &rt->line_out_notify);
+       cancel_delayed_work(&rt->headphone_notify.work);
+       cancel_delayed_work(&rt->line_in_notify.work);
+       cancel_delayed_work(&rt->line_out_notify.work);
+       flush_scheduled_work();
+       mutex_destroy(&rt->headphone_notify.mutex);
+       mutex_destroy(&rt->line_in_notify.mutex);
+       mutex_destroy(&rt->line_out_notify.mutex);
+}
+
+static irqreturn_t ftr_handle_notify_irq(int xx,
+                                        void *data,
+                                        struct pt_regs *regs)
+{
+       struct gpio_notification *notif = data;
+
+       schedule_work(&notif->work);
+
+       return IRQ_HANDLED;
+}
+
+static int ftr_set_notify(struct gpio_runtime *rt,
+                         enum notify_type type,
+                         notify_func_t notify,
+                         void *data)
+{
+       struct gpio_notification *notif;
+       notify_func_t old;
+       int irq;
+       char *name;
+       int err = -EBUSY;
+
+       switch (type) {
+       case AOA_NOTIFY_HEADPHONE:
+               notif = &rt->headphone_notify;
+               name = "headphone-detect";
+               irq = headphone_detect_irq;
+               break;
+       case AOA_NOTIFY_LINE_IN:
+               notif = &rt->line_in_notify;
+               name = "linein-detect";
+               irq = linein_detect_irq;
+               break;
+       case AOA_NOTIFY_LINE_OUT:
+               notif = &rt->line_out_notify;
+               name = "lineout-detect";
+               irq = lineout_detect_irq;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (irq == -1)
+               return -ENODEV;
+
+       mutex_lock(&notif->mutex);
+
+       old = notif->notify;
+
+       if (!old && !notify) {
+               err = 0;
+               goto out_unlock;
+       }
+
+       if (old && notify) {
+               if (old == notify && notif->data == data)
+                       err = 0;
+               goto out_unlock;
+       }
+
+       if (old && !notify)
+               free_irq(irq, notif);
+
+       if (!old && notify) {
+               err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif);
+               if (err)
+                       goto out_unlock;
+       }
+
+       notif->notify = notify;
+       notif->data = data;
+
+       err = 0;
+ out_unlock:
+       mutex_unlock(&notif->mutex);
+       return err;
+}
+
+static int ftr_get_detect(struct gpio_runtime *rt,
+                         enum notify_type type)
+{
+       int gpio, ret, active;
+
+       switch (type) {
+       case AOA_NOTIFY_HEADPHONE:
+               gpio = headphone_detect_gpio;
+               active = headphone_detect_gpio_activestate;
+               break;
+       case AOA_NOTIFY_LINE_IN:
+               gpio = linein_detect_gpio;
+               active = linein_detect_gpio_activestate;
+               break;
+       case AOA_NOTIFY_LINE_OUT:
+               gpio = lineout_detect_gpio;
+               active = lineout_detect_gpio_activestate;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (gpio == -1)
+               return -ENODEV;
+
+       ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0);
+       if (ret < 0)
+               return ret;
+       return ((ret >> 1) & 1) == active;
+}
+
+static struct gpio_methods methods = {
+       .init                   = ftr_gpio_init,
+       .exit                   = ftr_gpio_exit,
+       .all_amps_off           = ftr_gpio_all_amps_off,
+       .all_amps_restore       = ftr_gpio_all_amps_restore,
+       .set_headphone          = ftr_gpio_set_headphone,
+       .set_speakers           = ftr_gpio_set_amp,
+       .set_lineout            = ftr_gpio_set_lineout,
+       .set_hw_reset           = ftr_gpio_set_hw_reset,
+       .get_headphone          = ftr_gpio_get_headphone,
+       .get_speakers           = ftr_gpio_get_amp,
+       .get_lineout            = ftr_gpio_get_lineout,
+       .set_notify             = ftr_set_notify,
+       .get_detect             = ftr_get_detect,
+};
+
+struct gpio_methods *ftr_gpio_methods = &methods;
+EXPORT_SYMBOL_GPL(ftr_gpio_methods);
diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/snd-aoa-gpio-pmf.c
new file mode 100644 (file)
index 0000000..0e9b9bb
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Apple Onboard Audio pmf GPIOs
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+#include "../aoa.h"
+
+#define PMF_GPIO(name, bit)                                    \
+static void pmf_gpio_set_##name(struct gpio_runtime *rt, int on)\
+{                                                              \
+       struct pmf_args args = { .count = 1, .u[0].v = !on };   \
+                                                               \
+       if (unlikely(!rt)) return;                              \
+       pmf_call_function(rt->node, #name "-mute", &args);      \
+       rt->implementation_private &= ~(1<<bit);                \
+       rt->implementation_private |= (!!on << bit);            \
+}                                                              \
+static int pmf_gpio_get_##name(struct gpio_runtime *rt)                \
+{                                                              \
+       if (unlikely(!rt)) return 0;                            \
+       return (rt->implementation_private>>bit)&1;             \
+}
+
+PMF_GPIO(headphone, 0);
+PMF_GPIO(amp, 1);
+PMF_GPIO(lineout, 2);
+
+static void pmf_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
+{
+       struct pmf_args args = { .count = 1, .u[0].v = !!on };
+
+       if (unlikely(!rt)) return;
+       pmf_call_function(rt->node, "hw-reset", &args);
+}
+
+static void pmf_gpio_all_amps_off(struct gpio_runtime *rt)
+{
+       int saved;
+
+       if (unlikely(!rt)) return;
+       saved = rt->implementation_private;
+       pmf_gpio_set_headphone(rt, 0);
+       pmf_gpio_set_amp(rt, 0);
+       pmf_gpio_set_lineout(rt, 0);
+       rt->implementation_private = saved;
+}
+
+static void pmf_gpio_all_amps_restore(struct gpio_runtime *rt)
+{
+       int s;
+
+       if (unlikely(!rt)) return;
+       s = rt->implementation_private;
+       pmf_gpio_set_headphone(rt, (s>>0)&1);
+       pmf_gpio_set_amp(rt, (s>>1)&1);
+       pmf_gpio_set_lineout(rt, (s>>2)&1);
+}
+
+static void pmf_handle_notify(void *data)
+{
+       struct gpio_notification *notif = data;
+
+       mutex_lock(&notif->mutex);
+       if (notif->notify)
+               notif->notify(notif->data);
+       mutex_unlock(&notif->mutex);
+}
+
+static void pmf_gpio_init(struct gpio_runtime *rt)
+{
+       pmf_gpio_all_amps_off(rt);
+       rt->implementation_private = 0;
+       INIT_WORK(&rt->headphone_notify.work, pmf_handle_notify,
+                 &rt->headphone_notify);
+       INIT_WORK(&rt->line_in_notify.work, pmf_handle_notify,
+                 &rt->line_in_notify);
+       INIT_WORK(&rt->line_out_notify.work, pmf_handle_notify,
+                 &rt->line_out_notify);
+       mutex_init(&rt->headphone_notify.mutex);
+       mutex_init(&rt->line_in_notify.mutex);
+       mutex_init(&rt->line_out_notify.mutex);
+}
+
+static void pmf_gpio_exit(struct gpio_runtime *rt)
+{
+       pmf_gpio_all_amps_off(rt);
+       rt->implementation_private = 0;
+
+       if (rt->headphone_notify.gpio_private)
+               pmf_unregister_irq_client(rt->headphone_notify.gpio_private);
+       if (rt->line_in_notify.gpio_private)
+               pmf_unregister_irq_client(rt->line_in_notify.gpio_private);
+       if (rt->line_out_notify.gpio_private)
+               pmf_unregister_irq_client(rt->line_out_notify.gpio_private);
+
+       /* make sure no work is pending before freeing
+        * all things */
+       cancel_delayed_work(&rt->headphone_notify.work);
+       cancel_delayed_work(&rt->line_in_notify.work);
+       cancel_delayed_work(&rt->line_out_notify.work);
+       flush_scheduled_work();
+
+       mutex_destroy(&rt->headphone_notify.mutex);
+       mutex_destroy(&rt->line_in_notify.mutex);
+       mutex_destroy(&rt->line_out_notify.mutex);
+
+       if (rt->headphone_notify.gpio_private)
+               kfree(rt->headphone_notify.gpio_private);
+       if (rt->line_in_notify.gpio_private)
+               kfree(rt->line_in_notify.gpio_private);
+       if (rt->line_out_notify.gpio_private)
+               kfree(rt->line_out_notify.gpio_private);
+}
+
+static void pmf_handle_notify_irq(void *data)
+{
+       struct gpio_notification *notif = data;
+
+       schedule_work(&notif->work);
+}
+
+static int pmf_set_notify(struct gpio_runtime *rt,
+                         enum notify_type type,
+                         notify_func_t notify,
+                         void *data)
+{
+       struct gpio_notification *notif;
+       notify_func_t old;
+       struct pmf_irq_client *irq_client;
+       char *name;
+       int err = -EBUSY;
+
+       switch (type) {
+       case AOA_NOTIFY_HEADPHONE:
+               notif = &rt->headphone_notify;
+               name = "headphone-detect";
+               break;
+       case AOA_NOTIFY_LINE_IN:
+               notif = &rt->line_in_notify;
+               name = "linein-detect";
+               break;
+       case AOA_NOTIFY_LINE_OUT:
+               notif = &rt->line_out_notify;
+               name = "lineout-detect";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mutex_lock(&notif->mutex);
+
+       old = notif->notify;
+
+       if (!old && !notify) {
+               err = 0;
+               goto out_unlock;
+       }
+
+       if (old && notify) {
+               if (old == notify && notif->data == data)
+                       err = 0;
+               goto out_unlock;
+       }
+
+       if (old && !notify) {
+               irq_client = notif->gpio_private;
+               pmf_unregister_irq_client(irq_client);
+               kfree(irq_client);
+               notif->gpio_private = NULL;
+       }
+       if (!old && notify) {
+               irq_client = kzalloc(sizeof(struct pmf_irq_client),
+                                    GFP_KERNEL);
+               irq_client->data = notif;
+               irq_client->handler = pmf_handle_notify_irq;
+               irq_client->owner = THIS_MODULE;
+               err = pmf_register_irq_client(rt->node,
+                                             name,
+                                             irq_client);
+               if (err) {
+                       printk(KERN_ERR "snd-aoa: gpio layer failed to"
+                                       " register %s irq (%d)\n", name, err);
+                       kfree(irq_client);
+                       goto out_unlock;
+               }
+               notif->gpio_private = irq_client;
+       }
+       notif->notify = notify;
+       notif->data = data;
+
+       err = 0;
+ out_unlock:
+       mutex_unlock(&notif->mutex);
+       return err;
+}
+
+static int pmf_get_detect(struct gpio_runtime *rt,
+                         enum notify_type type)
+{
+       char *name;
+       int err = -EBUSY, ret;
+       struct pmf_args args = { .count = 1, .u[0].p = &ret };
+
+       switch (type) {
+       case AOA_NOTIFY_HEADPHONE:
+               name = "headphone-detect";
+               break;
+       case AOA_NOTIFY_LINE_IN:
+               name = "linein-detect";
+               break;
+       case AOA_NOTIFY_LINE_OUT:
+               name = "lineout-detect";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = pmf_call_function(rt->node, name, &args);
+       if (err)
+               return err;
+       return ret;
+}
+
+static struct gpio_methods methods = {
+       .init                   = pmf_gpio_init,
+       .exit                   = pmf_gpio_exit,
+       .all_amps_off           = pmf_gpio_all_amps_off,
+       .all_amps_restore       = pmf_gpio_all_amps_restore,
+       .set_headphone          = pmf_gpio_set_headphone,
+       .set_speakers           = pmf_gpio_set_amp,
+       .set_lineout            = pmf_gpio_set_lineout,
+       .set_hw_reset           = pmf_gpio_set_hw_reset,
+       .get_headphone          = pmf_gpio_get_headphone,
+       .get_speakers           = pmf_gpio_get_amp,
+       .get_lineout            = pmf_gpio_get_lineout,
+       .set_notify             = pmf_set_notify,
+       .get_detect             = pmf_get_detect,
+};
+
+struct gpio_methods *pmf_gpio_methods = &methods;
+EXPORT_SYMBOL_GPL(pmf_gpio_methods);
diff --git a/sound/aoa/fabrics/Kconfig b/sound/aoa/fabrics/Kconfig
new file mode 100644 (file)
index 0000000..c3bc770
--- /dev/null
@@ -0,0 +1,12 @@
+config SND_AOA_FABRIC_LAYOUT
+       tristate "layout-id fabric"
+       depends SND_AOA
+       select SND_AOA_SOUNDBUS
+       select SND_AOA_SOUNDBUS_I2S
+       ---help---
+       This enables the layout-id fabric for the Apple Onboard
+       Audio driver, the module holding it all together
+       based on the device-tree's layout-id property.
+       
+       If you are unsure and have a later Apple machine,
+       compile it as a module.
diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile
new file mode 100644 (file)
index 0000000..55fc5e7
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
new file mode 100644 (file)
index 0000000..04a7238
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ * Apple Onboard Audio driver -- layout fabric
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This fabric module looks for sound codecs
+ * based on the layout-id property in the device tree.
+ *
+ */
+
+#include <asm/prom.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa");
+
+#define MAX_CODECS_PER_BUS     2
+
+/* These are the connections the layout fabric
+ * knows about. It doesn't really care about the
+ * input ones, but I thought I'd separate them
+ * to give them proper names. The thing is that
+ * Apple usually will distinguish the active output
+ * by GPIOs, while the active input is set directly
+ * on the codec. Hence we here tell the codec what
+ * we think is connected. This information is hard-
+ * coded below ... */
+#define CC_SPEAKERS    (1<<0)
+#define CC_HEADPHONE   (1<<1)
+#define CC_LINEOUT     (1<<2)
+#define CC_DIGITALOUT  (1<<3)
+#define CC_LINEIN      (1<<4)
+#define CC_MICROPHONE  (1<<5)
+#define CC_DIGITALIN   (1<<6)
+/* pretty bogus but users complain...
+ * This is a flag saying that the LINEOUT
+ * should be renamed to HEADPHONE.
+ * be careful with input detection! */
+#define CC_LINEOUT_LABELLED_HEADPHONE  (1<<7)
+
+struct codec_connection {
+       /* CC_ flags from above */
+       int connected;
+       /* codec dependent bit to be set in the aoa_codec.connected field.
+        * This intentionally doesn't have any generic flags because the
+        * fabric has to know the codec anyway and all codecs might have
+        * different connectors */
+       int codec_bit;
+};
+
+struct codec_connect_info {
+       char *name;
+       struct codec_connection *connections;
+};
+
+#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF        (1<<0)
+
+struct layout {
+       unsigned int layout_id;
+       struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
+       int flags;
+       
+       /* if busname is not assigned, we use 'Master' below,
+        * so that our layout table doesn't need to be filled
+        * too much.
+        * We only assign these two if we expect to find more
+        * than one soundbus, i.e. on those machines with
+        * multiple layout-ids */
+       char *busname;
+       int pcmid;
+};
+
+MODULE_ALIAS("sound-layout-41");
+MODULE_ALIAS("sound-layout-45");
+MODULE_ALIAS("sound-layout-51");
+MODULE_ALIAS("sound-layout-58");
+MODULE_ALIAS("sound-layout-60");
+MODULE_ALIAS("sound-layout-61");
+MODULE_ALIAS("sound-layout-64");
+MODULE_ALIAS("sound-layout-65");
+MODULE_ALIAS("sound-layout-68");
+MODULE_ALIAS("sound-layout-69");
+MODULE_ALIAS("sound-layout-70");
+MODULE_ALIAS("sound-layout-72");
+MODULE_ALIAS("sound-layout-80");
+MODULE_ALIAS("sound-layout-82");
+MODULE_ALIAS("sound-layout-84");
+MODULE_ALIAS("sound-layout-86");
+MODULE_ALIAS("sound-layout-92");
+
+/* onyx with all but microphone connected */
+static struct codec_connection onyx_connections_nomic[] = {
+       {
+               .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_DIGITALOUT,
+               .codec_bit = 1,
+       },
+       {
+               .connected = CC_LINEIN,
+               .codec_bit = 2,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+/* onyx on machines without headphone */
+static struct codec_connection onyx_connections_noheadphones[] = {
+       {
+               .connected = CC_SPEAKERS | CC_LINEOUT |
+                            CC_LINEOUT_LABELLED_HEADPHONE,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_DIGITALOUT,
+               .codec_bit = 1,
+       },
+       /* FIXME: are these correct? probably not for all the machines
+        * below ... If not this will need separating. */
+       {
+               .connected = CC_LINEIN,
+               .codec_bit = 2,
+       },
+       {
+               .connected = CC_MICROPHONE,
+               .codec_bit = 3,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+/* onyx on machines with real line-out */
+static struct codec_connection onyx_connections_reallineout[] = {
+       {
+               .connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_DIGITALOUT,
+               .codec_bit = 1,
+       },
+       {
+               .connected = CC_LINEIN,
+               .codec_bit = 2,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines without line out */
+static struct codec_connection tas_connections_nolineout[] = {
+       {
+               .connected = CC_SPEAKERS | CC_HEADPHONE,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_LINEIN,
+               .codec_bit = 2,
+       },
+       {
+               .connected = CC_MICROPHONE,
+               .codec_bit = 3,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines with neither line out nor line in */
+static struct codec_connection tas_connections_noline[] = {
+       {
+               .connected = CC_SPEAKERS | CC_HEADPHONE,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_MICROPHONE,
+               .codec_bit = 3,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines without microphone */
+static struct codec_connection tas_connections_nomic[] = {
+       {
+               .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_LINEIN,
+               .codec_bit = 2,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines with everything connected */
+static struct codec_connection tas_connections_all[] = {
+       {
+               .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_LINEIN,
+               .codec_bit = 2,
+       },
+       {
+               .connected = CC_MICROPHONE,
+               .codec_bit = 3,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection toonie_connections[] = {
+       {
+               .connected = CC_SPEAKERS | CC_HEADPHONE,
+               .codec_bit = 0,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_input[] = {
+       {
+               .connected = CC_DIGITALIN,
+               .codec_bit = 0,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_output[] = {
+       {
+               .connected = CC_DIGITALOUT,
+               .codec_bit = 1,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_inout[] = {
+       {
+               .connected = CC_DIGITALIN,
+               .codec_bit = 0,
+       },
+       {
+               .connected = CC_DIGITALOUT,
+               .codec_bit = 1,
+       },
+       {} /* terminate array by .connected == 0 */
+};
+
+static struct layout layouts[] = {
+       /* last PowerBooks (15" Oct 2005) */
+       { .layout_id = 82,
+         .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+         .codecs[1] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       /* PowerMac9,1 */
+       { .layout_id = 60,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_reallineout,
+         },
+       },
+       /* PowerMac9,1 */
+       { .layout_id = 61,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       /* PowerBook5,7 */
+       { .layout_id = 64,
+         .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+       },
+       /* PowerBook5,7 */
+       { .layout_id = 65,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       /* PowerBook5,9 [17" Oct 2005] */
+       { .layout_id = 84,
+         .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+         .codecs[1] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       /* PowerMac8,1 */
+       { .layout_id = 45,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+         .codecs[1] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       /* Quad PowerMac (analog in, analog/digital out) */
+       { .layout_id = 68,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_nomic,
+         },
+       },
+       /* Quad PowerMac (digital in) */
+       { .layout_id = 69,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+         .busname = "digital in", .pcmid = 1 },
+       /* Early 2005 PowerBook (PowerBook 5,6) */
+       { .layout_id = 70,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_nolineout,
+         },
+       },
+       /* PowerBook 5,4 */
+       { .layout_id = 51,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_nolineout,
+         },
+       },
+       /* PowerBook6,7 */
+       { .layout_id = 80,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_noline,
+         },
+       },
+       /* PowerBook6,8 */
+       { .layout_id = 72,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_nolineout,
+         },
+       },
+       /* PowerMac8,2 */
+       { .layout_id = 86,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_nomic,
+         },
+         .codecs[1] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       /* PowerBook6,7 */
+       { .layout_id = 92,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_nolineout,
+         },
+       },
+       /* PowerMac10,1 (Mac Mini) */
+       { .layout_id = 58,
+         .codecs[0] = {
+               .name = "toonie",
+               .connections = toonie_connections,
+         },
+       },
+       /* unknown, untested, but this comes from Apple */
+       { .layout_id = 41,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_all,
+         },
+       },
+       { .layout_id = 36,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_nomic,
+         },
+         .codecs[1] = {
+               .name = "topaz",
+               .connections = topaz_inout,
+         },
+       },
+       { .layout_id = 47,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+       },
+       { .layout_id = 48,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       { .layout_id = 49,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_nomic,
+         },
+       },
+       { .layout_id = 50,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       { .layout_id = 56,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+       },
+       { .layout_id = 57,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       { .layout_id = 62,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+         .codecs[1] = {
+               .name = "topaz",
+               .connections = topaz_output,
+         },
+       },
+       { .layout_id = 66,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+       },
+       { .layout_id = 67,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+       },
+       { .layout_id = 76,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_nomic,
+         },
+         .codecs[1] = {
+               .name = "topaz",
+               .connections = topaz_inout,
+         },
+       },
+       { .layout_id = 90,
+         .codecs[0] = {
+               .name = "tas",
+               .connections = tas_connections_noline,
+         },
+       },
+       { .layout_id = 94,
+         .codecs[0] = {
+               .name = "onyx",
+               /* but it has an external mic?? how to select? */
+               .connections = onyx_connections_noheadphones,
+         },
+       },
+       { .layout_id = 96,
+         .codecs[0] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+       },
+       { .layout_id = 98,
+         .codecs[0] = {
+               .name = "toonie",
+               .connections = toonie_connections,
+         },
+       },
+       { .layout_id = 100,
+         .codecs[0] = {
+               .name = "topaz",
+               .connections = topaz_input,
+         },
+         .codecs[1] = {
+               .name = "onyx",
+               .connections = onyx_connections_noheadphones,
+         },
+       },
+       {}
+};
+
+static struct layout *find_layout_by_id(unsigned int id)
+{
+       struct layout *l;
+
+       l = layouts;
+       while (l->layout_id) {
+               if (l->layout_id == id)
+                       return l;
+               l++;
+       }
+       return NULL;
+}
+
+static void use_layout(struct layout *l)
+{
+       int i;
+
+       for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+               if (l->codecs[i].name) {
+                       request_module("snd-aoa-codec-%s", l->codecs[i].name);
+               }
+       }
+       /* now we wait for the codecs to call us back */
+}
+
+struct layout_dev;
+
+struct layout_dev_ptr {
+       struct layout_dev *ptr;
+};
+
+struct layout_dev {
+       struct list_head list;
+       struct soundbus_dev *sdev;
+       struct device_node *sound;
+       struct aoa_codec *codecs[MAX_CODECS_PER_BUS];
+       struct layout *layout;
+       struct gpio_runtime gpio;
+
+       /* we need these for headphone/lineout detection */
+       struct snd_kcontrol *headphone_ctrl;
+       struct snd_kcontrol *lineout_ctrl;
+       struct snd_kcontrol *speaker_ctrl;
+       struct snd_kcontrol *headphone_detected_ctrl;
+       struct snd_kcontrol *lineout_detected_ctrl;
+
+       struct layout_dev_ptr selfptr_headphone;
+       struct layout_dev_ptr selfptr_lineout;
+
+       u32 have_lineout_detect:1,
+           have_headphone_detect:1,
+           switch_on_headphone:1,
+           switch_on_lineout:1;
+};
+
+static LIST_HEAD(layouts_list);
+static int layouts_list_items;
+/* this can go away but only if we allow multiple cards,
+ * make the fabric handle all the card stuff, etc... */
+static struct layout_dev *layout_device;
+
+static int control_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+#define AMP_CONTROL(n, description)                                    \
+static int n##_control_get(struct snd_kcontrol *kcontrol,              \
+                          struct snd_ctl_elem_value *ucontrol)         \
+{                                                                      \
+       struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);        \
+       if (gpio->methods && gpio->methods->get_##n)                    \
+               ucontrol->value.integer.value[0] =                      \
+                       gpio->methods->get_##n(gpio);                   \
+       return 0;                                                       \
+}                                                                      \
+static int n##_control_put(struct snd_kcontrol *kcontrol,              \
+                          struct snd_ctl_elem_value *ucontrol)         \
+{                                                                      \
+       struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);        \
+       if (gpio->methods && gpio->methods->get_##n)                    \
+               gpio->methods->set_##n(gpio,                            \
+                       ucontrol->value.integer.value[0]);              \
+       return 1;                                                       \
+}                                                                      \
+static struct snd_kcontrol_new n##_ctl = {                             \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,                            \
+       .name = description,                                            \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,                      \
+       .info = control_info,                                           \
+       .get = n##_control_get,                                         \
+       .put = n##_control_put,                                         \
+}
+
+AMP_CONTROL(headphone, "Headphone Switch");
+AMP_CONTROL(speakers, "Speakers Switch");
+AMP_CONTROL(lineout, "Line-Out Switch");
+
+static int detect_choice_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+
+       switch (kcontrol->private_value) {
+       case 0:
+               ucontrol->value.integer.value[0] = ldev->switch_on_headphone;
+               break;
+       case 1:
+               ucontrol->value.integer.value[0] = ldev->switch_on_lineout;
+               break;
+       default:
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int detect_choice_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+
+       switch (kcontrol->private_value) {
+       case 0:
+               ldev->switch_on_headphone = !!ucontrol->value.integer.value[0];
+               break;
+       case 1:
+               ldev->switch_on_lineout = !!ucontrol->value.integer.value[0];
+               break;
+       default:
+               return -ENODEV;
+       }
+       return 1;
+}
+
+static struct snd_kcontrol_new headphone_detect_choice = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Headphone Detect Autoswitch",
+       .info = control_info,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .get = detect_choice_get,
+       .put = detect_choice_put,
+       .private_value = 0,
+};
+
+static struct snd_kcontrol_new lineout_detect_choice = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Line-Out Detect Autoswitch",
+       .info = control_info,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .get = detect_choice_get,
+       .put = detect_choice_put,
+       .private_value = 1,
+};
+
+static int detected_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+       int v;
+
+       switch (kcontrol->private_value) {
+       case 0:
+               v = ldev->gpio.methods->get_detect(&ldev->gpio,
+                                                  AOA_NOTIFY_HEADPHONE);
+               break;
+       case 1:
+               v = ldev->gpio.methods->get_detect(&ldev->gpio,
+                                                  AOA_NOTIFY_LINE_OUT);
+               break;
+       default:
+               return -ENODEV;
+       }
+       ucontrol->value.integer.value[0] = v;
+       return 0;
+}
+
+static struct snd_kcontrol_new headphone_detected = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Headphone Detected",
+       .info = control_info,
+       .access = SNDRV_CTL_ELEM_ACCESS_READ,
+       .get = detected_get,
+       .private_value = 0,
+};
+
+static struct snd_kcontrol_new lineout_detected = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Line-Out Detected",
+       .info = control_info,
+       .access = SNDRV_CTL_ELEM_ACCESS_READ,
+       .get = detected_get,
+       .private_value = 1,
+};
+
+static int check_codec(struct aoa_codec *codec,
+                      struct layout_dev *ldev,
+                      struct codec_connect_info *cci)
+{
+       u32 *ref;
+       char propname[32];
+       struct codec_connection *cc;
+
+       /* if the codec has a 'codec' node, we require a reference */
+       if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
+               snprintf(propname, sizeof(propname),
+                        "platform-%s-codec-ref", codec->name);
+               ref = (u32*)get_property(ldev->sound, propname, NULL);
+               if (!ref) {
+                       printk(KERN_INFO "snd-aoa-fabric-layout: "
+                               "required property %s not present\n", propname);
+                       return -ENODEV;
+               }
+               if (*ref != codec->node->linux_phandle) {
+                       printk(KERN_INFO "snd-aoa-fabric-layout: "
+                               "%s doesn't match!\n", propname);
+                       return -ENODEV;
+               }
+       } else {
+               if (layouts_list_items != 1) {
+                       printk(KERN_INFO "snd-aoa-fabric-layout: "
+                               "more than one soundbus, but no references.\n");
+                       return -ENODEV;
+               }
+       }
+       codec->soundbus_dev = ldev->sdev;
+       codec->gpio = &ldev->gpio;
+
+       cc = cci->connections;
+       if (!cc)
+               return -EINVAL;
+
+       printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n");
+
+       codec->connected = 0;
+       codec->fabric_data = cc;
+
+       while (cc->connected) {
+               codec->connected |= 1<<cc->codec_bit;
+               cc++;
+       }
+
+       return 0;
+}
+
+static int layout_found_codec(struct aoa_codec *codec)
+{
+       struct layout_dev *ldev;
+       int i;
+
+       list_for_each_entry(ldev, &layouts_list, list) {
+               for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+                       if (!ldev->layout->codecs[i].name)
+                               continue;
+                       if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) {
+                               if (check_codec(codec,
+                                               ldev,
+                                               &ldev->layout->codecs[i]) == 0)
+                                       return 0;
+                       }
+               }
+       }
+       return -ENODEV;
+}
+
+static void layout_remove_codec(struct aoa_codec *codec)
+{
+       int i;
+       /* here remove the codec from the layout dev's
+        * codec reference */
+
+       codec->soundbus_dev = NULL;
+       codec->gpio = NULL;
+       for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+       }
+}
+
+static void layout_notify(void *data)
+{
+       struct layout_dev_ptr *dptr = data;
+       struct layout_dev *ldev;
+       int v, update;
+       struct snd_kcontrol *detected, *c;
+       struct snd_card *card = aoa_get_card();
+
+       ldev = dptr->ptr;
+       if (data == &ldev->selfptr_headphone) {
+               v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE);
+               detected = ldev->headphone_detected_ctrl;
+               update = ldev->switch_on_headphone;
+               if (update) {
+                       ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
+                       ldev->gpio.methods->set_headphone(&ldev->gpio, v);
+                       ldev->gpio.methods->set_lineout(&ldev->gpio, 0);
+               }
+       } else if (data == &ldev->selfptr_lineout) {
+               v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT);
+               detected = ldev->lineout_detected_ctrl;
+               update = ldev->switch_on_lineout;
+               if (update) {
+                       ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
+                       ldev->gpio.methods->set_headphone(&ldev->gpio, 0);
+                       ldev->gpio.methods->set_lineout(&ldev->gpio, v);
+               }
+       } else
+               return;
+
+       if (detected)
+               snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id);
+       if (update) {
+               c = ldev->headphone_ctrl;
+               if (c)
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+               c = ldev->speaker_ctrl;
+               if (c)
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+               c = ldev->lineout_ctrl;
+               if (c)
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+       }
+}
+
+static void layout_attached_codec(struct aoa_codec *codec)
+{
+       struct codec_connection *cc;
+       struct snd_kcontrol *ctl;
+       int headphones, lineout;
+       struct layout_dev *ldev = layout_device;
+
+       /* need to add this codec to our codec array! */
+
+       cc = codec->fabric_data;
+
+       headphones = codec->gpio->methods->get_detect(codec->gpio,
+                                                     AOA_NOTIFY_HEADPHONE);
+       lineout = codec->gpio->methods->get_detect(codec->gpio,
+                                                  AOA_NOTIFY_LINE_OUT);
+
+       while (cc->connected) {
+               if (cc->connected & CC_SPEAKERS) {
+                       if (headphones <= 0 && lineout <= 0)
+                               ldev->gpio.methods->set_speakers(codec->gpio, 1);
+                       ctl = snd_ctl_new1(&speakers_ctl, codec->gpio);
+                       ldev->speaker_ctrl = ctl;
+                       aoa_snd_ctl_add(ctl);
+               }
+               if (cc->connected & CC_HEADPHONE) {
+                       if (headphones == 1)
+                               ldev->gpio.methods->set_headphone(codec->gpio, 1);
+                       ctl = snd_ctl_new1(&headphone_ctl, codec->gpio);
+                       ldev->headphone_ctrl = ctl;
+                       aoa_snd_ctl_add(ctl);
+                       ldev->have_headphone_detect =
+                               !ldev->gpio.methods
+                                       ->set_notify(&ldev->gpio,
+                                                    AOA_NOTIFY_HEADPHONE,
+                                                    layout_notify,
+                                                    &ldev->selfptr_headphone);
+                       if (ldev->have_headphone_detect) {
+                               ctl = snd_ctl_new1(&headphone_detect_choice,
+                                                  ldev);
+                               aoa_snd_ctl_add(ctl);
+                               ctl = snd_ctl_new1(&headphone_detected,
+                                                  ldev);
+                               ldev->headphone_detected_ctrl = ctl;
+                               aoa_snd_ctl_add(ctl);
+                       }
+               }
+               if (cc->connected & CC_LINEOUT) {
+                       if (lineout == 1)
+                               ldev->gpio.methods->set_lineout(codec->gpio, 1);
+                       ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
+                       if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+                               strlcpy(ctl->id.name,
+                                       "Headphone Switch", sizeof(ctl->id.name));
+                       ldev->lineout_ctrl = ctl;
+                       aoa_snd_ctl_add(ctl);
+                       ldev->have_lineout_detect =
+                               !ldev->gpio.methods
+                                       ->set_notify(&ldev->gpio,
+                                                    AOA_NOTIFY_LINE_OUT,
+                                                    layout_notify,
+                                                    &ldev->selfptr_lineout);
+                       if (ldev->have_lineout_detect) {
+                               ctl = snd_ctl_new1(&lineout_detect_choice,
+                                                  ldev);
+                               if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+                                       strlcpy(ctl->id.name,
+                                               "Headphone Detect Autoswitch",
+                                               sizeof(ctl->id.name));
+                               aoa_snd_ctl_add(ctl);
+                               ctl = snd_ctl_new1(&lineout_detected,
+                                                  ldev);
+                               if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+                                       strlcpy(ctl->id.name,
+                                               "Headphone Detected",
+                                               sizeof(ctl->id.name));
+                               ldev->lineout_detected_ctrl = ctl;
+                               aoa_snd_ctl_add(ctl);
+                       }
+               }
+               cc++;
+       }
+       /* now update initial state */
+       if (ldev->have_headphone_detect)
+               layout_notify(&ldev->selfptr_headphone);
+       if (ldev->have_lineout_detect)
+               layout_notify(&ldev->selfptr_lineout);
+}
+
+static struct aoa_fabric layout_fabric = {
+       .name = "SoundByLayout",
+       .owner = THIS_MODULE,
+       .found_codec = layout_found_codec,
+       .remove_codec = layout_remove_codec,
+       .attached_codec = layout_attached_codec,
+};
+
+static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
+{
+       struct device_node *sound = NULL;
+       unsigned int *layout_id;
+       struct layout *layout;
+       struct layout_dev *ldev = NULL;
+       int err;
+
+       /* hm, currently we can only have one ... */
+       if (layout_device)
+               return -ENODEV;
+
+       /* by breaking out we keep a reference */
+       while ((sound = of_get_next_child(sdev->ofdev.node, sound))) {
+               if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
+                       break;
+       }
+       if (!sound) return -ENODEV;
+
+       layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
+       if (!layout_id)
+               goto outnodev;
+       printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d ", *layout_id);
+
+       layout = find_layout_by_id(*layout_id);
+       if (!layout) {
+               printk("(no idea how to handle)\n");
+               goto outnodev;
+       }
+
+       ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL);
+       if (!ldev)
+               goto outnodev;
+
+       layout_device = ldev;
+       ldev->sdev = sdev;
+       ldev->sound = sound;
+       ldev->layout = layout;
+       ldev->gpio.node = sound->parent;
+       switch (layout->layout_id) {
+       case 41: /* that unknown machine no one seems to have */
+       case 51: /* PowerBook5,4 */
+       case 58: /* Mac Mini */
+               ldev->gpio.methods = ftr_gpio_methods;
+               break;
+       default:
+               ldev->gpio.methods = pmf_gpio_methods;
+       }
+       ldev->selfptr_headphone.ptr = ldev;
+       ldev->selfptr_lineout.ptr = ldev;
+       sdev->ofdev.dev.driver_data = ldev;
+
+       printk("(using)\n");
+       list_add(&ldev->list, &layouts_list);
+       layouts_list_items++;
+
+       /* assign these before registering ourselves, so
+        * callbacks that are done during registration
+        * already have the values */
+       sdev->pcmid = ldev->layout->pcmid;
+       if (ldev->layout->busname) {
+               sdev->pcmname = ldev->layout->busname;
+       } else {
+               sdev->pcmname = "Master";
+       }
+
+       ldev->gpio.methods->init(&ldev->gpio);
+
+       err = aoa_fabric_register(&layout_fabric);
+       if (err && err != -EALREADY) {
+               printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
+                                " another fabric is active!\n");
+               goto outlistdel;
+       }
+
+       use_layout(layout);
+       ldev->switch_on_headphone = 1;
+       ldev->switch_on_lineout = 1;
+       return 0;
+ outlistdel:
+       /* we won't be using these then... */
+       ldev->gpio.methods->exit(&ldev->gpio);
+       /* reset if we didn't use it */
+       sdev->pcmname = NULL;
+       sdev->pcmid = -1;
+       list_del(&ldev->list);
+       layouts_list_items--;
+ outnodev:
+       if (sound) of_node_put(sound);
+       layout_device = NULL;
+       if (ldev) kfree(ldev);
+       return -ENODEV;
+}
+
+static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
+{
+       struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+       int i;
+
+       for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+               if (ldev->codecs[i]) {
+                       aoa_fabric_unlink_codec(ldev->codecs[i]);
+               }
+               ldev->codecs[i] = NULL;
+       }
+       list_del(&ldev->list);
+       layouts_list_items--;
+       of_node_put(ldev->sound);
+
+       ldev->gpio.methods->set_notify(&ldev->gpio,
+                                      AOA_NOTIFY_HEADPHONE,
+                                      NULL,
+                                      NULL);
+       ldev->gpio.methods->set_notify(&ldev->gpio,
+                                      AOA_NOTIFY_LINE_OUT,
+                                      NULL,
+                                      NULL);
+
+       ldev->gpio.methods->exit(&ldev->gpio);
+       layout_device = NULL;
+       kfree(ldev);
+       sdev->pcmid = -1;
+       sdev->pcmname = NULL;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
+{
+       struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+
+       printk("aoa_fabric_layout_suspend()\n");
+
+       if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
+               ldev->gpio.methods->all_amps_off(&ldev->gpio);
+
+       return 0;
+}
+
+static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
+{
+       struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+
+       printk("aoa_fabric_layout_resume()\n");
+
+       if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
+               ldev->gpio.methods->all_amps_restore(&ldev->gpio);
+
+       return 0;
+}
+#endif
+
+static struct soundbus_driver aoa_soundbus_driver = {
+       .name = "snd_aoa_soundbus_drv",
+       .owner = THIS_MODULE,
+       .probe = aoa_fabric_layout_probe,
+       .remove = aoa_fabric_layout_remove,
+#ifdef CONFIG_PM
+       .suspend = aoa_fabric_layout_suspend,
+       .resume = aoa_fabric_layout_resume,
+#endif
+};
+
+static int __init aoa_fabric_layout_init(void)
+{
+       int err;
+
+       err = soundbus_register_driver(&aoa_soundbus_driver);
+       if (err)
+               return err;
+       return 0;
+}
+
+static void __exit aoa_fabric_layout_exit(void)
+{
+       soundbus_unregister_driver(&aoa_soundbus_driver);
+       aoa_fabric_unregister(&layout_fabric);
+}
+
+module_init(aoa_fabric_layout_init);
+module_exit(aoa_fabric_layout_exit);
diff --git a/sound/aoa/soundbus/Kconfig b/sound/aoa/soundbus/Kconfig
new file mode 100644 (file)
index 0000000..d532d27
--- /dev/null
@@ -0,0 +1,14 @@
+config SND_AOA_SOUNDBUS
+       tristate "Apple Soundbus support"
+       depends on SOUND && SND_PCM && EXPERIMENTAL
+       ---help---
+       This option enables the generic driver for the soundbus
+       support on Apple machines.
+       
+       It is required for the sound bus implementations.
+
+config SND_AOA_SOUNDBUS_I2S
+       tristate "I2S bus support"
+       depends on SND_AOA_SOUNDBUS && PCI
+       ---help---
+       This option enables support for Apple I2S busses.
diff --git a/sound/aoa/soundbus/Makefile b/sound/aoa/soundbus/Makefile
new file mode 100644 (file)
index 0000000..0e61f5a
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SND_AOA_SOUNDBUS) += snd-aoa-soundbus.o
+snd-aoa-soundbus-objs := core.o sysfs.o
+obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += i2sbus/
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
new file mode 100644 (file)
index 0000000..abe84a7
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * soundbus
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <linux/module.h>
+#include "soundbus.h"
+
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Apple Soundbus");
+
+struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev)
+{
+       struct device *tmp;
+
+       if (!dev)
+               return NULL;
+       tmp = get_device(&dev->ofdev.dev);
+       if (tmp)
+               return to_soundbus_device(tmp);
+       else
+               return NULL;
+}
+EXPORT_SYMBOL_GPL(soundbus_dev_get);
+
+void soundbus_dev_put(struct soundbus_dev *dev)
+{
+       if (dev)
+               put_device(&dev->ofdev.dev);
+}
+EXPORT_SYMBOL_GPL(soundbus_dev_put);
+
+static int soundbus_probe(struct device *dev)
+{
+       int error = -ENODEV;
+       struct soundbus_driver *drv;
+       struct soundbus_dev *soundbus_dev;
+
+       drv = to_soundbus_driver(dev->driver);
+       soundbus_dev = to_soundbus_device(dev);
+
+       if (!drv->probe)
+               return error;
+
+       soundbus_dev_get(soundbus_dev);
+
+       error = drv->probe(soundbus_dev);
+       if (error)
+               soundbus_dev_put(soundbus_dev);
+
+       return error;
+}
+
+
+static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
+                          char *buffer, int buffer_size)
+{
+       struct soundbus_dev * soundbus_dev;
+       struct of_device * of;
+       char *scratch, *compat, *compat2;
+       int i = 0;
+       int length, cplen, cplen2, seen = 0;
+
+       if (!dev)
+               return -ENODEV;
+
+       soundbus_dev = to_soundbus_device(dev);
+       if (!soundbus_dev)
+               return -ENODEV;
+
+       of = &soundbus_dev->ofdev;
+
+       /* stuff we want to pass to /sbin/hotplug */
+       envp[i++] = scratch = buffer;
+       length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
+       ++length;
+       buffer_size -= length;
+       if ((buffer_size <= 0) || (i >= num_envp))
+               return -ENOMEM;
+       scratch += length;
+
+       envp[i++] = scratch;
+       length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
+       ++length;
+       buffer_size -= length;
+       if ((buffer_size <= 0) || (i >= num_envp))
+               return -ENOMEM;
+       scratch += length;
+
+       /* Since the compatible field can contain pretty much anything
+        * it's not really legal to split it out with commas. We split it
+        * up using a number of environment variables instead. */
+
+       compat = (char *) get_property(of->node, "compatible", &cplen);
+       compat2 = compat;
+       cplen2= cplen;
+       while (compat && cplen > 0) {
+               envp[i++] = scratch;
+               length = scnprintf (scratch, buffer_size,
+                                    "OF_COMPATIBLE_%d=%s", seen, compat);
+               ++length;
+               buffer_size -= length;
+               if ((buffer_size <= 0) || (i >= num_envp))
+                       return -ENOMEM;
+               scratch += length;
+               length = strlen (compat) + 1;
+               compat += length;
+               cplen -= length;
+               seen++;
+       }
+
+       envp[i++] = scratch;
+       length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
+       ++length;
+       buffer_size -= length;
+       if ((buffer_size <= 0) || (i >= num_envp))
+               return -ENOMEM;
+       scratch += length;
+
+       envp[i++] = scratch;
+       length = scnprintf (scratch, buffer_size, "MODALIAS=%s",
+                       soundbus_dev->modalias);
+
+       buffer_size -= length;
+       if ((buffer_size <= 0) || (i >= num_envp))
+               return -ENOMEM;
+
+       envp[i] = NULL;
+
+       return 0;
+}
+
+static int soundbus_device_remove(struct device *dev)
+{
+       struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+       struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+       if (dev->driver && drv->remove)
+               drv->remove(soundbus_dev);
+       soundbus_dev_put(soundbus_dev);
+
+       return 0;
+}
+
+static void soundbus_device_shutdown(struct device *dev)
+{
+       struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+       struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(soundbus_dev);
+}
+
+#ifdef CONFIG_PM
+
+static int soundbus_device_suspend(struct device *dev, pm_message_t state)
+{
+       struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+       struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+       if (dev->driver && drv->suspend)
+               return drv->suspend(soundbus_dev, state);
+       return 0;
+}
+
+static int soundbus_device_resume(struct device * dev)
+{
+       struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
+       struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
+
+       if (dev->driver && drv->resume)
+               return drv->resume(soundbus_dev);
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+extern struct device_attribute soundbus_dev_attrs[];
+
+static struct bus_type soundbus_bus_type = {
+       .name           = "aoa-soundbus",
+       .probe          = soundbus_probe,
+       .uevent         = soundbus_uevent,
+       .remove         = soundbus_device_remove,
+       .shutdown       = soundbus_device_shutdown,
+#ifdef CONFIG_PM
+       .suspend        = soundbus_device_suspend,
+       .resume         = soundbus_device_resume,
+#endif
+       .dev_attrs      = soundbus_dev_attrs,
+};
+
+static int __init soundbus_init(void)
+{
+       return bus_register(&soundbus_bus_type);
+}
+
+static void __exit soundbus_exit(void)
+{
+       bus_unregister(&soundbus_bus_type);
+}
+
+int soundbus_add_one(struct soundbus_dev *dev)
+{
+       static int devcount;
+
+       /* sanity checks */
+       if (!dev->attach_codec ||
+           !dev->ofdev.node ||
+           dev->pcmname ||
+           dev->pcmid != -1) {
+               printk(KERN_ERR "soundbus: adding device failed sanity check!\n");
+               return -EINVAL;
+       }
+
+       snprintf(dev->ofdev.dev.bus_id, BUS_ID_SIZE, "soundbus:%x", ++devcount);
+       dev->ofdev.dev.bus = &soundbus_bus_type;
+       return of_device_register(&dev->ofdev);
+}
+EXPORT_SYMBOL_GPL(soundbus_add_one);
+
+void soundbus_remove_one(struct soundbus_dev *dev)
+{
+       of_device_unregister(&dev->ofdev);
+}
+EXPORT_SYMBOL_GPL(soundbus_remove_one);
+
+int soundbus_register_driver(struct soundbus_driver *drv)
+{
+       /* initialize common driver fields */
+       drv->driver.name = drv->name;
+       drv->driver.bus = &soundbus_bus_type;
+
+       /* register with core */
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(soundbus_register_driver);
+
+void soundbus_unregister_driver(struct soundbus_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(soundbus_unregister_driver);
+
+module_init(soundbus_init);
+module_exit(soundbus_exit);
diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile
new file mode 100644 (file)
index 0000000..e57a5cf
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o
+snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/i2sbus-control.c
new file mode 100644 (file)
index 0000000..f504079
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * i2sbus driver -- bus control routines
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <asm/prom.h>
+#include <asm/macio.h>
+#include <asm/pmac_feature.h>
+#include <asm/pmac_pfunc.h>
+#include "i2sbus.h"
+
+int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c)
+{
+       *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL);
+       if (!*c)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&(*c)->list);
+
+       if (of_address_to_resource(dev->ofdev.node, 0, &(*c)->rsrc))
+               goto err;
+       /* we really should be using feature calls instead of mapping
+        * these registers. It's safe for now since no one else is
+        * touching them... */
+       (*c)->controlregs = ioremap((*c)->rsrc.start,
+                                   sizeof(struct i2s_control_regs));
+       if (!(*c)->controlregs)
+               goto err;
+
+       return 0;
+ err:
+       kfree(*c);
+       *c = NULL;
+       return -ENODEV;
+}
+
+void i2sbus_control_destroy(struct i2sbus_control *c)
+{
+       iounmap(c->controlregs);
+       kfree(c);
+}
+
+/* this is serialised externally */
+int i2sbus_control_add_dev(struct i2sbus_control *c,
+                          struct i2sbus_dev *i2sdev)
+{
+       struct device_node *np;
+
+       np = i2sdev->sound.ofdev.node;
+       i2sdev->enable = pmf_find_function(np, "enable");
+       i2sdev->cell_enable = pmf_find_function(np, "cell-enable");
+       i2sdev->clock_enable = pmf_find_function(np, "clock-enable");
+       i2sdev->cell_disable = pmf_find_function(np, "cell-disable");
+       i2sdev->clock_disable = pmf_find_function(np, "clock-disable");
+
+       /* if the bus number is not 0 or 1 we absolutely need to use
+        * the platform functions -- there's nothing in Darwin that
+        * would allow seeing a system behind what the FCRs are then,
+        * and I don't want to go parsing a bunch of platform functions
+        * by hand to try finding a system... */
+       if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 &&
+           (!i2sdev->enable ||
+            !i2sdev->cell_enable || !i2sdev->clock_enable ||
+            !i2sdev->cell_disable || !i2sdev->clock_disable)) {
+               pmf_put_function(i2sdev->enable);
+               pmf_put_function(i2sdev->cell_enable);
+               pmf_put_function(i2sdev->clock_enable);
+               pmf_put_function(i2sdev->cell_disable);
+               pmf_put_function(i2sdev->clock_disable);
+               return -ENODEV;
+       }
+
+       list_add(&i2sdev->item, &c->list);
+
+       return 0;
+}
+
+void i2sbus_control_remove_dev(struct i2sbus_control *c,
+                              struct i2sbus_dev *i2sdev)
+{
+       /* this is serialised externally */
+       list_del(&i2sdev->item);
+       if (list_empty(&c->list))
+               i2sbus_control_destroy(c);
+}
+
+int i2sbus_control_enable(struct i2sbus_control *c,
+                         struct i2sbus_dev *i2sdev)
+{
+       struct pmf_args args = { .count = 0 };
+       int cc;
+
+       if (i2sdev->enable)
+               return pmf_call_one(i2sdev->enable, &args);
+
+       switch (i2sdev->bus_number) {
+       case 0:
+               cc = in_le32(&c->controlregs->cell_control);
+               out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_0_ENABLE);
+               break;
+       case 1:
+               cc = in_le32(&c->controlregs->cell_control);
+               out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_1_ENABLE);
+               break;
+       default:
+               return -ENODEV;
+       }
+       return 0;
+}
+
+int i2sbus_control_cell(struct i2sbus_control *c,
+                       struct i2sbus_dev *i2sdev,
+                       int enable)
+{
+       struct pmf_args args = { .count = 0 };
+       int cc;
+
+       switch (enable) {
+       case 0:
+               if (i2sdev->cell_disable)
+                       return pmf_call_one(i2sdev->cell_disable, &args);
+               break;
+       case 1:
+               if (i2sdev->cell_enable)
+                       return pmf_call_one(i2sdev->cell_enable, &args);
+               break;
+       default:
+               printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n");
+               return -ENODEV;
+       }
+       switch (i2sdev->bus_number) {
+       case 0:
+               cc = in_le32(&c->controlregs->cell_control);
+               cc &= ~CTRL_CLOCK_CELL_0_ENABLE;
+               cc |= enable * CTRL_CLOCK_CELL_0_ENABLE;
+               out_le32(&c->controlregs->cell_control, cc);
+               break;
+       case 1:
+               cc = in_le32(&c->controlregs->cell_control);
+               cc &= ~CTRL_CLOCK_CELL_1_ENABLE;
+               cc |= enable * CTRL_CLOCK_CELL_1_ENABLE;
+               out_le32(&c->controlregs->cell_control, cc);
+               break;
+       default:
+               return -ENODEV;
+       }
+       return 0;
+}
+
+int i2sbus_control_clock(struct i2sbus_control *c,
+                        struct i2sbus_dev *i2sdev,
+                        int enable)
+{
+       struct pmf_args args = { .count = 0 };
+       int cc;
+
+       switch (enable) {
+       case 0:
+               if (i2sdev->clock_disable)
+                       return pmf_call_one(i2sdev->clock_disable, &args);
+               break;
+       case 1:
+               if (i2sdev->clock_enable)
+                       return pmf_call_one(i2sdev->clock_enable, &args);
+               break;
+       default:
+               printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n");
+               return -ENODEV;
+       }
+       switch (i2sdev->bus_number) {
+       case 0:
+               cc = in_le32(&c->controlregs->cell_control);
+               cc &= ~CTRL_CLOCK_CLOCK_0_ENABLE;
+               cc |= enable * CTRL_CLOCK_CLOCK_0_ENABLE;
+               out_le32(&c->controlregs->cell_control, cc);
+               break;
+       case 1:
+               cc = in_le32(&c->controlregs->cell_control);
+               cc &= ~CTRL_CLOCK_CLOCK_1_ENABLE;
+               cc |= enable * CTRL_CLOCK_CLOCK_1_ENABLE;
+               out_le32(&c->controlregs->cell_control, cc);
+               break;
+       default:
+               return -ENODEV;
+       }
+       return 0;
+}
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.h b/sound/aoa/soundbus/i2sbus/i2sbus-control.h
new file mode 100644 (file)
index 0000000..bb05550
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * i2sbus driver -- bus register definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __I2SBUS_CONTROLREGS_H
+#define __I2SBUS_CONTROLREGS_H
+
+/* i2s control registers, at least what we know about them */
+
+#define __PAD(m,n) u8 __pad##m[n]
+#define _PAD(line, n) __PAD(line, n)
+#define PAD(n) _PAD(__LINE__, (n))
+struct i2s_control_regs {
+       PAD(0x38);
+       __le32 fcr0;            /* 0x38 (unknown) */
+       __le32 cell_control;    /* 0x3c (fcr1) */
+       __le32 fcr2;            /* 0x40 (unknown) */
+       __le32 fcr3;            /* 0x44 (fcr3) */
+       __le32 clock_control;   /* 0x48 (unknown) */
+       PAD(4);
+       /* total size: 0x50 bytes */
+}  __attribute__((__packed__));
+
+#define CTRL_CLOCK_CELL_0_ENABLE       (1<<10)
+#define CTRL_CLOCK_CLOCK_0_ENABLE      (1<<12)
+#define CTRL_CLOCK_SWRESET_0           (1<<11)
+#define CTRL_CLOCK_INTF_0_ENABLE       (1<<13)
+
+#define CTRL_CLOCK_CELL_1_ENABLE       (1<<17)
+#define CTRL_CLOCK_CLOCK_1_ENABLE      (1<<18)
+#define CTRL_CLOCK_SWRESET_1           (1<<19)
+#define CTRL_CLOCK_INTF_1_ENABLE       (1<<20)
+
+#endif /* __I2SBUS_CONTROLREGS_H */
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
new file mode 100644 (file)
index 0000000..f268dac
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * i2sbus driver
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <linux/module.h>
+#include <asm/macio.h>
+#include <asm/dbdma.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <linux/dma-mapping.h>
+#include "../soundbus.h"
+#include "i2sbus.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_DESCRIPTION("Apple Soundbus: I2S support");
+/* for auto-loading, declare that we handle this weird
+ * string that macio puts into the relevant device */
+MODULE_ALIAS("of:Ni2sTi2sC");
+
+static struct of_device_id i2sbus_match[] = {
+       { .name = "i2s" },
+       { }
+};
+
+static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
+                                      struct dbdma_command_mem *r,
+                                      int numcmds)
+{
+       /* one more for rounding */
+       r->size = (numcmds+1) * sizeof(struct dbdma_cmd);
+       /* We use the PCI APIs for now until the generic one gets fixed
+        * enough or until we get some macio-specific versions
+        */
+       r->space = dma_alloc_coherent(
+                       &macio_get_pci_dev(i2sdev->macio)->dev,
+                       r->size,
+                       &r->bus_addr,
+                       GFP_KERNEL);
+
+       if (!r->space) return -ENOMEM;
+
+       memset(r->space, 0, r->size);
+       r->cmds = (void*)DBDMA_ALIGN(r->space);
+       r->bus_cmd_start = r->bus_addr +
+                          (dma_addr_t)((char*)r->cmds - (char*)r->space);
+
+       return 0;
+}
+
+static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
+                                      struct dbdma_command_mem *r)
+{
+       if (!r->space) return;
+       
+       dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev,
+                           r->size, r->space, r->bus_addr);
+}
+
+static void i2sbus_release_dev(struct device *dev)
+{
+       struct i2sbus_dev *i2sdev;
+       int i;
+
+       i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev);
+
+       if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
+       if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
+       if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
+       for (i=0;i<3;i++)
+               if (i2sdev->allocated_resource[i])
+                       release_and_free_resource(i2sdev->allocated_resource[i]);
+       free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
+       free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring);
+       for (i=0;i<3;i++)
+               free_irq(i2sdev->interrupts[i], i2sdev);
+       i2sbus_control_remove_dev(i2sdev->control, i2sdev);
+       mutex_destroy(&i2sdev->lock);
+       kfree(i2sdev);
+}
+
+static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs)
+{
+       struct i2sbus_dev *dev = devid;
+       u32 intreg;
+
+       spin_lock(&dev->low_lock);
+       intreg = in_le32(&dev->intfregs->intr_ctl);
+
+       /* acknowledge interrupt reasons */
+       out_le32(&dev->intfregs->intr_ctl, intreg);
+
+       spin_unlock(&dev->low_lock);
+
+       return IRQ_HANDLED;
+}
+
+static int force;
+module_param(force, int, 0444);
+MODULE_PARM_DESC(force, "Force loading i2sbus even when"
+                       " no layout-id property is present");
+
+/* FIXME: look at device node refcounting */
+static int i2sbus_add_dev(struct macio_dev *macio,
+                         struct i2sbus_control *control,
+                         struct device_node *np)
+{
+       struct i2sbus_dev *dev;
+       struct device_node *child = NULL, *sound = NULL;
+       int i;
+       static const char *rnames[] = { "i2sbus: %s (control)",
+                                       "i2sbus: %s (tx)",
+                                       "i2sbus: %s (rx)" };
+       static irqreturn_t (*ints[])(int irq, void *devid,
+                                    struct pt_regs *regs) = {
+               i2sbus_bus_intr,
+               i2sbus_tx_intr,
+               i2sbus_rx_intr
+       };
+
+       if (strlen(np->name) != 5)
+               return 0;
+       if (strncmp(np->name, "i2s-", 4))
+               return 0;
+
+       if (np->n_intrs != 3)
+               return 0;
+
+       dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
+       if (!dev)
+               return 0;
+
+       i = 0;
+       while ((child = of_get_next_child(np, child))) {
+               if (strcmp(child->name, "sound") == 0) {
+                       i++;
+                       sound = child;
+               }
+       }
+       if (i == 1) {
+               u32 *layout_id;
+               layout_id = (u32*) get_property(sound, "layout-id", NULL);
+               if (layout_id) {
+                       snprintf(dev->sound.modalias, 32,
+                                "sound-layout-%d", *layout_id);
+                       force = 1;
+               }
+       }
+       /* for the time being, until we can handle non-layout-id
+        * things in some fabric, refuse to attach if there is no
+        * layout-id property or we haven't been forced to attach.
+        * When there are two i2s busses and only one has a layout-id,
+        * then this depends on the order, but that isn't important
+        * either as the second one in that case is just a modem. */
+       if (!force) {
+               kfree(dev);
+               return -ENODEV;
+       }
+
+       mutex_init(&dev->lock);
+       spin_lock_init(&dev->low_lock);
+       dev->sound.ofdev.node = np;
+       dev->sound.ofdev.dma_mask = macio->ofdev.dma_mask;
+       dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.dma_mask;
+       dev->sound.ofdev.dev.parent = &macio->ofdev.dev;
+       dev->sound.ofdev.dev.release = i2sbus_release_dev;
+       dev->sound.attach_codec = i2sbus_attach_codec;
+       dev->sound.detach_codec = i2sbus_detach_codec;
+       dev->sound.pcmid = -1;
+       dev->macio = macio;
+       dev->control = control;
+       dev->bus_number = np->name[4] - 'a';
+       INIT_LIST_HEAD(&dev->sound.codec_list);
+
+       for (i=0;i<3;i++) {
+               dev->interrupts[i] = -1;
+               snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name);
+       }
+       for (i=0;i<3;i++) {
+               if (request_irq(np->intrs[i].line, ints[i], 0, dev->rnames[i], dev))
+                       goto err;
+               dev->interrupts[i] = np->intrs[i].line;
+       }
+
+       for (i=0;i<3;i++) {
+               if (of_address_to_resource(np, i, &dev->resources[i]))
+                       goto err;
+               /* if only we could use our resource dev->resources[i]...
+                * but request_resource doesn't know about parents and
+                * contained resources... */
+               dev->allocated_resource[i] = 
+                       request_mem_region(dev->resources[i].start,
+                                          dev->resources[i].end -
+                                          dev->resources[i].start + 1,
+                                          dev->rnames[i]);
+               if (!dev->allocated_resource[i]) {
+                       printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i);
+                       goto err;
+               }
+       }
+       /* should do sanity checking here about length of them */
+       dev->intfregs = ioremap(dev->resources[0].start,
+                               dev->resources[0].end-dev->resources[0].start+1);
+       dev->out.dbdma = ioremap(dev->resources[1].start,
+                                dev->resources[1].end-dev->resources[1].start+1);
+       dev->in.dbdma = ioremap(dev->resources[2].start,
+                               dev->resources[2].end-dev->resources[2].start+1);
+       if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma)
+               goto err;
+
+       if (alloc_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring,
+                                       MAX_DBDMA_COMMANDS))
+               goto err;
+       if (alloc_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring,
+                                       MAX_DBDMA_COMMANDS))
+               goto err;
+
+       if (i2sbus_control_add_dev(dev->control, dev)) {
+               printk(KERN_ERR "i2sbus: control layer didn't like bus\n");
+               goto err;
+       }
+
+       if (soundbus_add_one(&dev->sound)) {
+               printk(KERN_DEBUG "i2sbus: device registration error!\n");
+               goto err;
+       }
+
+       /* enable this cell */
+       i2sbus_control_cell(dev->control, dev, 1);
+       i2sbus_control_enable(dev->control, dev);
+       i2sbus_control_clock(dev->control, dev, 1);
+
+       return 1;
+ err:
+       for (i=0;i<3;i++)
+               if (dev->interrupts[i] != -1)
+                       free_irq(dev->interrupts[i], dev);
+       free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring);
+       free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring);
+       if (dev->intfregs) iounmap(dev->intfregs);
+       if (dev->out.dbdma) iounmap(dev->out.dbdma);
+       if (dev->in.dbdma) iounmap(dev->in.dbdma);
+       for (i=0;i<3;i++)
+               if (dev->allocated_resource[i])
+                       release_and_free_resource(dev->allocated_resource[i]);
+       mutex_destroy(&dev->lock);
+       kfree(dev);
+       return 0;
+}
+
+static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
+{
+       struct device_node *np = NULL;
+       int got = 0, err;
+       struct i2sbus_control *control = NULL;
+
+       err = i2sbus_control_init(dev, &control);
+       if (err)
+               return err;
+       if (!control) {
+               printk(KERN_ERR "i2sbus_control_init API breakage\n");
+               return -ENODEV;
+       }
+
+       while ((np = of_get_next_child(dev->ofdev.node, np))) {
+               if (device_is_compatible(np, "i2sbus") ||
+                   device_is_compatible(np, "i2s-modem")) {
+                       got += i2sbus_add_dev(dev, control, np);
+               }
+       }
+
+       if (!got) {
+               /* found none, clean up */
+               i2sbus_control_destroy(control);
+               return -ENODEV;
+       }
+
+       dev->ofdev.dev.driver_data = control;
+
+       return 0;
+}
+
+static int i2sbus_remove(struct macio_dev* dev)
+{
+       struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+       struct i2sbus_dev *i2sdev, *tmp;
+
+       list_for_each_entry_safe(i2sdev, tmp, &control->list, item)
+               soundbus_remove_one(&i2sdev->sound);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
+{
+       struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+       struct codec_info_item *cii;
+       struct i2sbus_dev* i2sdev;
+       int err, ret = 0;
+
+       list_for_each_entry(i2sdev, &control->list, item) {
+               /* Notify Alsa */
+               if (i2sdev->sound.pcm) {
+                       /* Suspend PCM streams */
+                       snd_pcm_suspend_all(i2sdev->sound.pcm);
+                       /* Probably useless as we handle
+                        * power transitions ourselves */
+                       snd_power_change_state(i2sdev->sound.pcm->card,
+                                              SNDRV_CTL_POWER_D3hot);
+               }
+               /* Notify codecs */
+               list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+                       err = 0;
+                       if (cii->codec->suspend)
+                               err = cii->codec->suspend(cii, state);
+                       if (err)
+                               ret = err;
+               }
+       }
+       return ret;
+}
+
+static int i2sbus_resume(struct macio_dev* dev)
+{
+       struct i2sbus_control *control = dev->ofdev.dev.driver_data;
+       struct codec_info_item *cii;
+       struct i2sbus_dev* i2sdev;
+       int err, ret = 0;
+
+       list_for_each_entry(i2sdev, &control->list, item) {
+               /* Notify codecs so they can re-initialize */
+               list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+                       err = 0;
+                       if (cii->codec->resume)
+                               err = cii->codec->resume(cii);
+                       if (err)
+                               ret = err;
+               }
+               /* Notify Alsa */
+               if (i2sdev->sound.pcm) {
+                       /* Same comment as above, probably useless */
+                       snd_power_change_state(i2sdev->sound.pcm->card,
+                                              SNDRV_CTL_POWER_D0);
+               }
+       }
+
+       return ret;
+}
+#endif /* CONFIG_PM */
+
+static int i2sbus_shutdown(struct macio_dev* dev)
+{
+       return 0;
+}
+
+static struct macio_driver i2sbus_drv = {
+       .name = "soundbus-i2s",
+       .owner = THIS_MODULE,
+       .match_table = i2sbus_match,
+       .probe = i2sbus_probe,
+       .remove = i2sbus_remove,
+#ifdef CONFIG_PM
+       .suspend = i2sbus_suspend,
+       .resume = i2sbus_resume,
+#endif
+       .shutdown = i2sbus_shutdown,
+};
+
+static int __init soundbus_i2sbus_init(void)
+{
+       return macio_register_driver(&i2sbus_drv);
+}
+
+static void __exit soundbus_i2sbus_exit(void)
+{
+       macio_unregister_driver(&i2sbus_drv);
+}
+
+module_init(soundbus_i2sbus_init);
+module_exit(soundbus_i2sbus_exit);
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h
new file mode 100644 (file)
index 0000000..c6b5f54
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * i2sbus driver -- interface register definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __I2SBUS_INTERFACE_H
+#define __I2SBUS_INTERFACE_H
+
+/* i2s bus control registers, at least what we know about them */
+
+#define __PAD(m,n) u8 __pad##m[n]
+#define _PAD(line, n) __PAD(line, n)
+#define PAD(n) _PAD(__LINE__, (n))
+struct i2s_interface_regs {
+       __le32 intr_ctl;        /* 0x00 */
+       PAD(12);
+       __le32 serial_format;   /* 0x10 */
+       PAD(12);
+       __le32 codec_msg_out;   /* 0x20 */
+       PAD(12);
+       __le32 codec_msg_in;    /* 0x30 */
+       PAD(12);
+       __le32 frame_count;     /* 0x40 */
+       PAD(12);
+       __le32 frame_match;     /* 0x50 */
+       PAD(12);
+       __le32 data_word_sizes; /* 0x60 */
+       PAD(12);
+       __le32 peak_level_sel;  /* 0x70 */
+       PAD(12);
+       __le32 peak_level_in0;  /* 0x80 */
+       PAD(12);
+       __le32 peak_level_in1;  /* 0x90 */
+       PAD(12);
+       /* total size: 0x100 bytes */
+}  __attribute__((__packed__));
+
+/* interrupt register is just a bitfield with
+ * interrupt enable and pending bits */
+#define I2S_REG_INTR_CTL               0x00
+#      define I2S_INT_FRAME_COUNT              (1<<31)
+#      define I2S_PENDING_FRAME_COUNT          (1<<30)
+#      define I2S_INT_MESSAGE_FLAG             (1<<29)
+#      define I2S_PENDING_MESSAGE_FLAG         (1<<28)
+#      define I2S_INT_NEW_PEAK                 (1<<27)
+#      define I2S_PENDING_NEW_PEAK             (1<<26)
+#      define I2S_INT_CLOCKS_STOPPED           (1<<25)
+#      define I2S_PENDING_CLOCKS_STOPPED       (1<<24)
+#      define I2S_INT_EXTERNAL_SYNC_ERROR      (1<<23)
+#      define I2S_PENDING_EXTERNAL_SYNC_ERROR  (1<<22)
+#      define I2S_INT_EXTERNAL_SYNC_OK         (1<<21)
+#      define I2S_PENDING_EXTERNAL_SYNC_OK     (1<<20)
+#      define I2S_INT_NEW_SAMPLE_RATE          (1<<19)
+#      define I2S_PENDING_NEW_SAMPLE_RATE      (1<<18)
+#      define I2S_INT_STATUS_FLAG              (1<<17)
+#      define I2S_PENDING_STATUS_FLAG          (1<<16)
+
+/* serial format register is more interesting :)
+ * It contains:
+ *  - clock source
+ *  - MClk divisor
+ *  - SClk divisor
+ *  - SClk master flag
+ *  - serial format (sony, i2s 64x, i2s 32x, dav, silabs)
+ *  - external sample frequency interrupt (don't understand)
+ *  - external sample frequency
+ */
+#define I2S_REG_SERIAL_FORMAT          0x10
+/* clock source. You get either 18.432, 45.1584 or 49.1520 MHz */
+#      define I2S_SF_CLOCK_SOURCE_SHIFT        30
+#      define I2S_SF_CLOCK_SOURCE_MASK         (3<<I2S_SF_CLOCK_SOURCE_SHIFT)
+#      define I2S_SF_CLOCK_SOURCE_18MHz        (0<<I2S_SF_CLOCK_SOURCE_SHIFT)
+#      define I2S_SF_CLOCK_SOURCE_45MHz        (1<<I2S_SF_CLOCK_SOURCE_SHIFT)
+#      define I2S_SF_CLOCK_SOURCE_49MHz        (2<<I2S_SF_CLOCK_SOURCE_SHIFT)
+/* also, let's define the exact clock speeds here, in Hz */
+#define I2S_CLOCK_SPEED_18MHz  18432000
+#define I2S_CLOCK_SPEED_45MHz  45158400
+#define I2S_CLOCK_SPEED_49MHz  49152000
+/* MClk is the clock that drives the codec, usually called its 'system clock'.
+ * It is derived by taking only every 'divisor' tick of the clock.
+ */
+#      define I2S_SF_MCLKDIV_SHIFT             24
+#      define I2S_SF_MCLKDIV_MASK              (0x1F<<I2S_SF_MCLKDIV_SHIFT)
+#      define I2S_SF_MCLKDIV_1                 (0x14<<I2S_SF_MCLKDIV_SHIFT)
+#      define I2S_SF_MCLKDIV_3                 (0x13<<I2S_SF_MCLKDIV_SHIFT)
+#      define I2S_SF_MCLKDIV_5                 (0x12<<I2S_SF_MCLKDIV_SHIFT)
+#      define I2S_SF_MCLKDIV_14                (0x0E<<I2S_SF_MCLKDIV_SHIFT)
+#      define I2S_SF_MCLKDIV_OTHER(div)        (((div/2-1)<<I2S_SF_MCLKDIV_SHIFT)&I2S_SF_MCLKDIV_MASK)
+static inline int i2s_sf_mclkdiv(int div, int *out)
+{
+       int d;
+
+       switch(div) {
+       case 1: *out |= I2S_SF_MCLKDIV_1; return 0;
+       case 3: *out |= I2S_SF_MCLKDIV_3; return 0;
+       case 5: *out |= I2S_SF_MCLKDIV_5; return 0;
+       case 14: *out |= I2S_SF_MCLKDIV_14; return 0;
+       default:
+               if (div%2) return -1;
+               d = div/2-1;
+               if (d == 0x14 || d == 0x13 || d == 0x12 || d == 0x0E)
+                       return -1;
+               *out |= I2S_SF_MCLKDIV_OTHER(div);
+               return 0;
+       }
+}
+/* SClk is the clock that drives the i2s wire bus. Note that it is
+ * derived from the MClk above by taking only every 'divisor' tick
+ * of MClk.
+ */
+#      define I2S_SF_SCLKDIV_SHIFT             20
+#      define I2S_SF_SCLKDIV_MASK              (0xF<<I2S_SF_SCLKDIV_SHIFT)
+#      define I2S_SF_SCLKDIV_1                 (8<<I2S_SF_SCLKDIV_SHIFT)
+#      define I2S_SF_SCLKDIV_3                 (9<<I2S_SF_SCLKDIV_SHIFT)
+#      define I2S_SF_SCLKDIV_OTHER(div)        (((div/2-1)<<I2S_SF_SCLKDIV_SHIFT)&I2S_SF_SCLKDIV_MASK)
+static inline int i2s_sf_sclkdiv(int div, int *out)
+{
+       int d;
+
+       switch(div) {
+       case 1: *out |= I2S_SF_SCLKDIV_1; return 0;
+       case 3: *out |= I2S_SF_SCLKDIV_3; return 0;
+       default:
+               if (div%2) return -1;
+               d = div/2-1;
+               if (d == 8 || d == 9) return -1;
+               *out |= I2S_SF_SCLKDIV_OTHER(div);
+               return 0;
+       }
+}
+#      define I2S_SF_SCLK_MASTER               (1<<19)
+/* serial format is the way the data is put to the i2s wire bus */
+#      define I2S_SF_SERIAL_FORMAT_SHIFT       16
+#      define I2S_SF_SERIAL_FORMAT_MASK        (7<<I2S_SF_SERIAL_FORMAT_SHIFT)
+#      define I2S_SF_SERIAL_FORMAT_SONY        (0<<I2S_SF_SERIAL_FORMAT_SHIFT)
+#      define I2S_SF_SERIAL_FORMAT_I2S_64X     (1<<I2S_SF_SERIAL_FORMAT_SHIFT)
+#      define I2S_SF_SERIAL_FORMAT_I2S_32X     (2<<I2S_SF_SERIAL_FORMAT_SHIFT)
+#      define I2S_SF_SERIAL_FORMAT_I2S_DAV     (4<<I2S_SF_SERIAL_FORMAT_SHIFT)
+#      define I2S_SF_SERIAL_FORMAT_I2S_SILABS  (5<<I2S_SF_SERIAL_FORMAT_SHIFT)
+/* unknown */
+#      define I2S_SF_EXT_SAMPLE_FREQ_INT_SHIFT 12
+#      define I2S_SF_EXT_SAMPLE_FREQ_INT_MASK  (0xF<<I2S_SF_SAMPLE_FREQ_INT_SHIFT)
+/* probably gives external frequency? */
+#      define I2S_SF_EXT_SAMPLE_FREQ_MASK      0xFFF
+
+/* used to send codec messages, but how isn't clear */
+#define I2S_REG_CODEC_MSG_OUT          0x20
+
+/* used to receive codec messages, but how isn't clear */
+#define I2S_REG_CODEC_MSG_IN           0x30
+
+/* frame count reg isn't clear to me yet, but probably useful */
+#define I2S_REG_FRAME_COUNT            0x40
+
+/* program to some value, and get interrupt if frame count reaches it */
+#define I2S_REG_FRAME_MATCH            0x50
+
+/* this register describes how the bus transfers data */
+#define I2S_REG_DATA_WORD_SIZES                0x60
+/* number of interleaved input channels */
+#      define I2S_DWS_NUM_CHANNELS_IN_SHIFT    24
+#      define I2S_DWS_NUM_CHANNELS_IN_MASK     (0x1F<<I2S_DWS_NUM_CHANNELS_IN_SHIFT)
+/* word size of input data */
+#      define I2S_DWS_DATA_IN_SIZE_SHIFT       16
+#      define I2S_DWS_DATA_IN_16BIT            (0<<I2S_DWS_DATA_IN_SIZE_SHIFT)
+#      define I2S_DWS_DATA_IN_24BIT            (3<<I2S_DWS_DATA_IN_SIZE_SHIFT)
+/* number of interleaved output channels */
+#      define I2S_DWS_NUM_CHANNELS_OUT_SHIFT   8
+#      define I2S_DWS_NUM_CHANNELS_OUT_MASK    (0x1F<<I2S_DWS_NUM_CHANNELS_OUT_SHIFT)
+/* word size of output data */
+#      define I2S_DWS_DATA_OUT_SIZE_SHIFT      0
+#      define I2S_DWS_DATA_OUT_16BIT           (0<<I2S_DWS_DATA_OUT_SIZE_SHIFT)
+#      define I2S_DWS_DATA_OUT_24BIT           (3<<I2S_DWS_DATA_OUT_SIZE_SHIFT)
+
+
+/* unknown */
+#define I2S_REG_PEAK_LEVEL_SEL         0x70
+
+/* unknown */
+#define I2S_REG_PEAK_LEVEL_IN0         0x80
+
+/* unknown */
+#define I2S_REG_PEAK_LEVEL_IN1         0x90
+
+#endif /* __I2SBUS_INTERFACE_H */
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
new file mode 100644 (file)
index 0000000..3049015
--- /dev/null
@@ -0,0 +1,1021 @@
+/*
+ * i2sbus driver -- pcm routines
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+/* So apparently there's a reason for requiring driver.h
+ * to be included first, even if I don't know it... */
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <asm/macio.h>
+#include <linux/pci.h>
+#include "../soundbus.h"
+#include "i2sbus.h"
+
+static inline void get_pcm_info(struct i2sbus_dev *i2sdev, int in,
+                               struct pcm_info **pi, struct pcm_info **other)
+{
+       if (in) {
+               if (pi)
+                       *pi = &i2sdev->in;
+               if (other)
+                       *other = &i2sdev->out;
+       } else {
+               if (pi)
+                       *pi = &i2sdev->out;
+               if (other)
+                       *other = &i2sdev->in;
+       }
+}
+
+static int clock_and_divisors(int mclk, int sclk, int rate, int *out)
+{
+       /* sclk must be derived from mclk! */
+       if (mclk % sclk)
+               return -1;
+       /* derive sclk register value */
+       if (i2s_sf_sclkdiv(mclk / sclk, out))
+               return -1;
+
+       if (I2S_CLOCK_SPEED_18MHz % (rate * mclk) == 0) {
+               if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) {
+                       *out |= I2S_SF_CLOCK_SOURCE_18MHz;
+                       return 0;
+               }
+       }
+       if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) {
+               if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) {
+                       *out |= I2S_SF_CLOCK_SOURCE_45MHz;
+                       return 0;
+               }
+       }
+       if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) {
+               if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) {
+                       *out |= I2S_SF_CLOCK_SOURCE_49MHz;
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+#define CHECK_RATE(rate)                                               \
+       do { if (rates & SNDRV_PCM_RATE_ ##rate) {                      \
+               int dummy;                                              \
+               if (clock_and_divisors(sysclock_factor,                 \
+                                      bus_factor, rate, &dummy))       \
+                       rates &= ~SNDRV_PCM_RATE_ ##rate;               \
+       } } while (0)
+
+static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
+{
+       struct pcm_info *pi, *other;
+       struct soundbus_dev *sdev;
+       int masks_inited = 0, err;
+       struct codec_info_item *cii, *rev;
+       struct snd_pcm_hardware *hw;
+       u64 formats = 0;
+       unsigned int rates = 0;
+       struct transfer_info v;
+       int result = 0;
+       int bus_factor = 0, sysclock_factor = 0;
+       int found_this;
+
+       mutex_lock(&i2sdev->lock);
+
+       get_pcm_info(i2sdev, in, &pi, &other);
+
+       hw = &pi->substream->runtime->hw;
+       sdev = &i2sdev->sound;
+
+       if (pi->active) {
+               /* alsa messed up */
+               result = -EBUSY;
+               goto out_unlock;
+       }
+
+       /* we now need to assign the hw */
+       list_for_each_entry(cii, &sdev->codec_list, list) {
+               struct transfer_info *ti = cii->codec->transfers;
+               bus_factor = cii->codec->bus_factor;
+               sysclock_factor = cii->codec->sysclock_factor;
+               while (ti->formats && ti->rates) {
+                       v = *ti;
+                       if (ti->transfer_in == in
+                           && cii->codec->usable(cii, ti, &v)) {
+                               if (masks_inited) {
+                                       formats &= v.formats;
+                                       rates &= v.rates;
+                               } else {
+                                       formats = v.formats;
+                                       rates = v.rates;
+                                       masks_inited = 1;
+                               }
+                       }
+                       ti++;
+               }
+       }
+       if (!masks_inited || !bus_factor || !sysclock_factor) {
+               result = -ENODEV;
+               goto out_unlock;
+       }
+       /* bus dependent stuff */
+       hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+                  SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME;
+
+       CHECK_RATE(5512);
+       CHECK_RATE(8000);
+       CHECK_RATE(11025);
+       CHECK_RATE(16000);
+       CHECK_RATE(22050);
+       CHECK_RATE(32000);
+       CHECK_RATE(44100);
+       CHECK_RATE(48000);
+       CHECK_RATE(64000);
+       CHECK_RATE(88200);
+       CHECK_RATE(96000);
+       CHECK_RATE(176400);
+       CHECK_RATE(192000);
+       hw->rates = rates;
+
+       /* well. the codec might want 24 bits only, and we'll
+        * ever only transfer 24 bits, but they are top-aligned!
+        * So for alsa, we claim that we're doing full 32 bit
+        * while in reality we'll ignore the lower 8 bits of
+        * that when doing playback (they're transferred as 0
+        * as far as I know, no codecs we have are 32-bit capable
+        * so I can't really test) and when doing recording we'll
+        * always have those lower 8 bits recorded as 0 */
+       if (formats & SNDRV_PCM_FMTBIT_S24_BE)
+               formats |= SNDRV_PCM_FMTBIT_S32_BE;
+       if (formats & SNDRV_PCM_FMTBIT_U24_BE)
+               formats |= SNDRV_PCM_FMTBIT_U32_BE;
+       /* now mask off what we can support. I suppose we could
+        * also support S24_3LE and some similar formats, but I
+        * doubt there's a codec that would be able to use that,
+        * so we don't support it here. */
+       hw->formats = formats & (SNDRV_PCM_FMTBIT_S16_BE |
+                                SNDRV_PCM_FMTBIT_U16_BE |
+                                SNDRV_PCM_FMTBIT_S32_BE |
+                                SNDRV_PCM_FMTBIT_U32_BE);
+
+       /* we need to set the highest and lowest rate possible.
+        * These are the highest and lowest rates alsa can
+        * support properly in its bitfield.
+        * Below, we'll use that to restrict to the rate
+        * currently in use (if any). */
+       hw->rate_min = 5512;
+       hw->rate_max = 192000;
+       /* if the other stream is active, then we can only
+        * support what it is currently using.
+        * FIXME: I lied. This comment is wrong. We can support
+        * anything that works with the same serial format, ie.
+        * when recording 24 bit sound we can well play 16 bit
+        * sound at the same time iff using the same transfer mode.
+        */
+       if (other->active) {
+               /* FIXME: is this guaranteed by the alsa api? */
+               hw->formats &= (1ULL << i2sdev->format);
+               /* see above, restrict rates to the one we already have */
+               hw->rate_min = i2sdev->rate;
+               hw->rate_max = i2sdev->rate;
+       }
+
+       hw->channels_min = 2;
+       hw->channels_max = 2;
+       /* these are somewhat arbitrary */
+       hw->buffer_bytes_max = 131072;
+       hw->period_bytes_min = 256;
+       hw->period_bytes_max = 16384;
+       hw->periods_min = 3;
+       hw->periods_max = MAX_DBDMA_COMMANDS;
+       list_for_each_entry(cii, &sdev->codec_list, list) {
+               if (cii->codec->open) {
+                       err = cii->codec->open(cii, pi->substream);
+                       if (err) {
+                               result = err;
+                               /* unwind */
+                               found_this = 0;
+                               list_for_each_entry_reverse(rev,
+                                   &sdev->codec_list, list) {
+                                       if (found_this && rev->codec->close) {
+                                               rev->codec->close(rev,
+                                                               pi->substream);
+                                       }
+                                       if (rev == cii)
+                                               found_this = 1;
+                               }
+                               goto out_unlock;
+                       }
+               }
+       }
+
+ out_unlock:
+       mutex_unlock(&i2sdev->lock);
+       return result;
+}
+
+#undef CHECK_RATE
+
+static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
+{
+       struct codec_info_item *cii;
+       struct pcm_info *pi;
+       int err = 0, tmp;
+
+       mutex_lock(&i2sdev->lock);
+
+       get_pcm_info(i2sdev, in, &pi, NULL);
+
+       list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+               if (cii->codec->close) {
+                       tmp = cii->codec->close(cii, pi->substream);
+                       if (tmp)
+                               err = tmp;
+               }
+       }
+
+       pi->substream = NULL;
+       pi->active = 0;
+       mutex_unlock(&i2sdev->lock);
+       return err;
+}
+
+static int i2sbus_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params)
+{
+       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int i2sbus_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
+{
+       /* whee. Hard work now. The user has selected a bitrate
+        * and bit format, so now we have to program our
+        * I2S controller appropriately. */
+       struct snd_pcm_runtime *runtime;
+       struct dbdma_cmd *command;
+       int i, periodsize;
+       dma_addr_t offset;
+       struct bus_info bi;
+       struct codec_info_item *cii;
+       int sfr = 0;            /* serial format register */
+       int dws = 0;            /* data word sizes reg */
+       int input_16bit;
+       struct pcm_info *pi, *other;
+       int cnt;
+       int result = 0;
+
+       mutex_lock(&i2sdev->lock);
+
+       get_pcm_info(i2sdev, in, &pi, &other);
+
+       if (pi->dbdma_ring.running) {
+               result = -EBUSY;
+               goto out_unlock;
+       }
+
+       runtime = pi->substream->runtime;
+       pi->active = 1;
+       if (other->active &&
+           ((i2sdev->format != runtime->format)
+            || (i2sdev->rate != runtime->rate))) {
+               result = -EINVAL;
+               goto out_unlock;
+       }
+
+       i2sdev->format = runtime->format;
+       i2sdev->rate = runtime->rate;
+
+       periodsize = snd_pcm_lib_period_bytes(pi->substream);
+       pi->current_period = 0;
+
+       /* generate dbdma command ring first */
+       command = pi->dbdma_ring.cmds;
+       offset = runtime->dma_addr;
+       for (i = 0; i < pi->substream->runtime->periods;
+            i++, command++, offset += periodsize) {
+               memset(command, 0, sizeof(struct dbdma_cmd));
+               command->command =
+                   cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS);
+               command->phy_addr = cpu_to_le32(offset);
+               command->req_count = cpu_to_le16(periodsize);
+               command->xfer_status = cpu_to_le16(0);
+       }
+       /* last one branches back to first */
+       command--;
+       command->command |= cpu_to_le16(BR_ALWAYS);
+       command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
+
+       /* ok, let's set the serial format and stuff */
+       switch (runtime->format) {
+       /* 16 bit formats */
+       case SNDRV_PCM_FORMAT_S16_BE:
+       case SNDRV_PCM_FORMAT_U16_BE:
+               /* FIXME: if we add different bus factors we need to
+                * do more here!! */
+               bi.bus_factor = 0;
+               list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+                       bi.bus_factor = cii->codec->bus_factor;
+                       break;
+               }
+               if (!bi.bus_factor) {
+                       result = -ENODEV;
+                       goto out_unlock;
+               }
+               input_16bit = 1;
+               break;
+       case SNDRV_PCM_FORMAT_S32_BE:
+       case SNDRV_PCM_FORMAT_U32_BE:
+               /* force 64x bus speed, otherwise the data cannot be
+                * transferred quickly enough! */
+               bi.bus_factor = 64;
+               input_16bit = 0;
+               break;
+       default:
+               result = -EINVAL;
+               goto out_unlock;
+       }
+       /* we assume all sysclocks are the same! */
+       list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+               bi.sysclock_factor = cii->codec->sysclock_factor;
+               break;
+       }
+
+       if (clock_and_divisors(bi.sysclock_factor,
+                              bi.bus_factor,
+                              runtime->rate,
+                              &sfr) < 0) {
+               result = -EINVAL;
+               goto out_unlock;
+       }
+       switch (bi.bus_factor) {
+       case 32:
+               sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
+               break;
+       case 64:
+               sfr |= I2S_SF_SERIAL_FORMAT_I2S_64X;
+               break;
+       }
+       /* FIXME: THIS ASSUMES MASTER ALL THE TIME */
+       sfr |= I2S_SF_SCLK_MASTER;
+
+       list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
+               int err = 0;
+               if (cii->codec->prepare)
+                       err = cii->codec->prepare(cii, &bi, pi->substream);
+               if (err) {
+                       result = err;
+                       goto out_unlock;
+               }
+       }
+       /* codecs are fine with it, so set our clocks */
+       if (input_16bit)
+               dws =   (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) |
+                       (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) |
+                       I2S_DWS_DATA_IN_16BIT | I2S_DWS_DATA_OUT_16BIT;
+       else
+               dws =   (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) |
+                       (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) |
+                       I2S_DWS_DATA_IN_24BIT | I2S_DWS_DATA_OUT_24BIT;
+
+       /* early exit if already programmed correctly */
+       /* not locking these is fine since we touch them only in this function */
+       if (in_le32(&i2sdev->intfregs->serial_format) == sfr
+        && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
+               goto out_unlock;
+
+       /* let's notify the codecs about clocks going away.
+        * For now we only do mastering on the i2s cell... */
+       list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+               if (cii->codec->switch_clock)
+                       cii->codec->switch_clock(cii, CLOCK_SWITCH_PREPARE_SLAVE);
+
+       i2sbus_control_enable(i2sdev->control, i2sdev);
+       i2sbus_control_cell(i2sdev->control, i2sdev, 1);
+
+       out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED);
+
+       i2sbus_control_clock(i2sdev->control, i2sdev, 0);
+
+       msleep(1);
+
+       /* wait for clock stopped. This can apparently take a while... */
+       cnt = 100;
+       while (cnt-- &&
+           !(in_le32(&i2sdev->intfregs->intr_ctl) & I2S_PENDING_CLOCKS_STOPPED)) {
+               msleep(5);
+       }
+       out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED);
+
+       /* not locking these is fine since we touch them only in this function */
+       out_le32(&i2sdev->intfregs->serial_format, sfr);
+       out_le32(&i2sdev->intfregs->data_word_sizes, dws);
+
+        i2sbus_control_enable(i2sdev->control, i2sdev);
+        i2sbus_control_cell(i2sdev->control, i2sdev, 1);
+        i2sbus_control_clock(i2sdev->control, i2sdev, 1);
+       msleep(1);
+
+       list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+               if (cii->codec->switch_clock)
+                       cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
+
+ out_unlock:
+       mutex_unlock(&i2sdev->lock);
+       return result;
+}
+
+static struct dbdma_cmd STOP_CMD = {
+       .command = __constant_cpu_to_le16(DBDMA_STOP),
+};
+
+static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
+{
+       struct codec_info_item *cii;
+       struct pcm_info *pi;
+       int timeout;
+       struct dbdma_cmd tmp;
+       int result = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&i2sdev->low_lock, flags);
+
+       get_pcm_info(i2sdev, in, &pi, NULL);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               if (pi->dbdma_ring.running) {
+                       result = -EALREADY;
+                       goto out_unlock;
+               }
+               list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+                       if (cii->codec->start)
+                               cii->codec->start(cii, pi->substream);
+               pi->dbdma_ring.running = 1;
+
+               /* reset dma engine */
+               out_le32(&pi->dbdma->control,
+                        0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
+               timeout = 100;
+               while (in_le32(&pi->dbdma->status) & RUN && timeout--)
+                       udelay(1);
+               if (timeout <= 0) {
+                       printk(KERN_ERR
+                              "i2sbus: error waiting for dma reset\n");
+                       result = -ENXIO;
+                       goto out_unlock;
+               }
+
+               /* write dma command buffer address to the dbdma chip */
+               out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
+               /* post PCI write */
+               mb();
+               (void)in_le32(&pi->dbdma->status);
+
+               /* change first command to STOP */
+               tmp = *pi->dbdma_ring.cmds;
+               *pi->dbdma_ring.cmds = STOP_CMD;
+
+               /* set running state, remember that the first command is STOP */
+               out_le32(&pi->dbdma->control, RUN | (RUN << 16));
+               timeout = 100;
+               /* wait for STOP to be executed */
+               while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--)
+                       udelay(1);
+               if (timeout <= 0) {
+                       printk(KERN_ERR "i2sbus: error waiting for dma stop\n");
+                       result = -ENXIO;
+                       goto out_unlock;
+               }
+               /* again, write dma command buffer address to the dbdma chip,
+                * this time of the first real command */
+               *pi->dbdma_ring.cmds = tmp;
+               out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
+               /* post write */
+               mb();
+               (void)in_le32(&pi->dbdma->status);
+
+               /* reset dma engine again */
+               out_le32(&pi->dbdma->control,
+                        0 | (RUN | PAUSE | FLUSH | WAKE) << 16);
+               timeout = 100;
+               while (in_le32(&pi->dbdma->status) & RUN && timeout--)
+                       udelay(1);
+               if (timeout <= 0) {
+                       printk(KERN_ERR
+                              "i2sbus: error waiting for dma reset\n");
+                       result = -ENXIO;
+                       goto out_unlock;
+               }
+
+               /* wake up the chip with the next descriptor */
+               out_le32(&pi->dbdma->control,
+                        (RUN | WAKE) | ((RUN | WAKE) << 16));
+               /* get the frame count  */
+               pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
+
+               /* off you go! */
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (!pi->dbdma_ring.running) {
+                       result = -EALREADY;
+                       goto out_unlock;
+               }
+
+               /* turn off all relevant bits */
+               out_le32(&pi->dbdma->control,
+                        (RUN | WAKE | FLUSH | PAUSE) << 16);
+               {
+                       /* FIXME: move to own function */
+                       int timeout = 5000;
+                       while ((in_le32(&pi->dbdma->status) & RUN)
+                              && --timeout > 0)
+                               udelay(1);
+                       if (!timeout)
+                               printk(KERN_ERR
+                                      "i2sbus: timed out turning "
+                                      "off dbdma engine!\n");
+               }
+
+               pi->dbdma_ring.running = 0;
+               list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
+                       if (cii->codec->stop)
+                               cii->codec->stop(cii, pi->substream);
+               break;
+       default:
+               result = -EINVAL;
+               goto out_unlock;
+       }
+
+ out_unlock:
+       spin_unlock_irqrestore(&i2sdev->low_lock, flags);
+       return result;
+}
+
+static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
+{
+       struct pcm_info *pi;
+       u32 fc;
+
+       get_pcm_info(i2sdev, in, &pi, NULL);
+
+       fc = in_le32(&i2sdev->intfregs->frame_count);
+       fc = fc - pi->frame_count;
+
+       return (bytes_to_frames(pi->substream->runtime,
+                       pi->current_period *
+                       snd_pcm_lib_period_bytes(pi->substream))
+               + fc) % pi->substream->runtime->buffer_size;
+}
+
+static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
+{
+       struct pcm_info *pi;
+       u32 fc;
+       u32 delta;
+
+       spin_lock(&i2sdev->low_lock);
+       get_pcm_info(i2sdev, in, &pi, NULL);
+
+       if (!pi->dbdma_ring.running) {
+               /* there was still an interrupt pending
+                * while we stopped. or maybe another
+                * processor (not the one that was stopping
+                * the DMA engine) was spinning above
+                * waiting for the lock. */
+               goto out_unlock;
+       }
+
+       fc = in_le32(&i2sdev->intfregs->frame_count);
+       /* a counter overflow does not change the calculation. */
+       delta = fc - pi->frame_count;
+
+       /* update current_period */
+       while (delta >= pi->substream->runtime->period_size) {
+               pi->current_period++;
+               delta = delta - pi->substream->runtime->period_size;
+       }
+
+       if (unlikely(delta)) {
+               /* Some interrupt came late, so check the dbdma.
+                * This special case exists to syncronize the frame_count with
+                * the dbdma transfer, but is hit every once in a while. */
+               int period;
+
+               period = (in_le32(&pi->dbdma->cmdptr)
+                       - pi->dbdma_ring.bus_cmd_start)
+                               / sizeof(struct dbdma_cmd);
+               pi->current_period = pi->current_period
+                                       % pi->substream->runtime->periods;
+
+               while (pi->current_period != period) {
+                       pi->current_period++;
+                       pi->current_period %= pi->substream->runtime->periods;
+                       /* Set delta to zero, as the frame_count value is too
+                        * high (otherwise the code path will not be executed).
+                        * This corrects the fact that the frame_count is too
+                        * low at the beginning due to buffering. */
+                       delta = 0;
+               }
+       }
+
+       pi->frame_count = fc - delta;
+       pi->current_period %= pi->substream->runtime->periods;
+
+       spin_unlock(&i2sdev->low_lock);
+       /* may call _trigger again, hence needs to be unlocked */
+       snd_pcm_period_elapsed(pi->substream);
+       return;
+ out_unlock:
+       spin_unlock(&i2sdev->low_lock);
+}
+
+irqreturn_t i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+       handle_interrupt((struct i2sbus_dev *)devid, 0);
+       return IRQ_HANDLED;
+}
+
+irqreturn_t i2sbus_rx_intr(int irq, void *devid, struct pt_regs * regs)
+{
+       handle_interrupt((struct i2sbus_dev *)devid, 1);
+       return IRQ_HANDLED;
+}
+
+static int i2sbus_playback_open(struct snd_pcm_substream *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       i2sdev->out.substream = substream;
+       return i2sbus_pcm_open(i2sdev, 0);
+}
+
+static int i2sbus_playback_close(struct snd_pcm_substream *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+       int err;
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->out.substream != substream)
+               return -EINVAL;
+       err = i2sbus_pcm_close(i2sdev, 0);
+       if (!err)
+               i2sdev->out.substream = NULL;
+       return err;
+}
+
+static int i2sbus_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->out.substream != substream)
+               return -EINVAL;
+       return i2sbus_pcm_prepare(i2sdev, 0);
+}
+
+static int i2sbus_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->out.substream != substream)
+               return -EINVAL;
+       return i2sbus_pcm_trigger(i2sdev, 0, cmd);
+}
+
+static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
+                                                *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->out.substream != substream)
+               return 0;
+       return i2sbus_pcm_pointer(i2sdev, 0);
+}
+
+static struct snd_pcm_ops i2sbus_playback_ops = {
+       .open =         i2sbus_playback_open,
+       .close =        i2sbus_playback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    i2sbus_hw_params,
+       .hw_free =      i2sbus_hw_free,
+       .prepare =      i2sbus_playback_prepare,
+       .trigger =      i2sbus_playback_trigger,
+       .pointer =      i2sbus_playback_pointer,
+};
+
+static int i2sbus_record_open(struct snd_pcm_substream *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       i2sdev->in.substream = substream;
+       return i2sbus_pcm_open(i2sdev, 1);
+}
+
+static int i2sbus_record_close(struct snd_pcm_substream *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+       int err;
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->in.substream != substream)
+               return -EINVAL;
+       err = i2sbus_pcm_close(i2sdev, 1);
+       if (!err)
+               i2sdev->in.substream = NULL;
+       return err;
+}
+
+static int i2sbus_record_prepare(struct snd_pcm_substream *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->in.substream != substream)
+               return -EINVAL;
+       return i2sbus_pcm_prepare(i2sdev, 1);
+}
+
+static int i2sbus_record_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->in.substream != substream)
+               return -EINVAL;
+       return i2sbus_pcm_trigger(i2sdev, 1, cmd);
+}
+
+static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
+                                              *substream)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
+
+       if (!i2sdev)
+               return -EINVAL;
+       if (i2sdev->in.substream != substream)
+               return 0;
+       return i2sbus_pcm_pointer(i2sdev, 1);
+}
+
+static struct snd_pcm_ops i2sbus_record_ops = {
+       .open =         i2sbus_record_open,
+       .close =        i2sbus_record_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    i2sbus_hw_params,
+       .hw_free =      i2sbus_hw_free,
+       .prepare =      i2sbus_record_prepare,
+       .trigger =      i2sbus_record_trigger,
+       .pointer =      i2sbus_record_pointer,
+};
+
+static void i2sbus_private_free(struct snd_pcm *pcm)
+{
+       struct i2sbus_dev *i2sdev = snd_pcm_chip(pcm);
+       struct codec_info_item *p, *tmp;
+
+       i2sdev->sound.pcm = NULL;
+       i2sdev->out.created = 0;
+       i2sdev->in.created = 0;
+       list_for_each_entry_safe(p, tmp, &i2sdev->sound.codec_list, list) {
+               printk(KERN_ERR "i2sbus: a codec didn't unregister!\n");
+               list_del(&p->list);
+               module_put(p->codec->owner);
+               kfree(p);
+       }
+       soundbus_dev_put(&i2sdev->sound);
+       module_put(THIS_MODULE);
+}
+
+/* FIXME: this function needs an error handling strategy with labels */
+int
+i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
+                   struct codec_info *ci, void *data)
+{
+       int err, in = 0, out = 0;
+       struct transfer_info *tmp;
+       struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev);
+       struct codec_info_item *cii;
+
+       if (!dev->pcmname || dev->pcmid == -1) {
+               printk(KERN_ERR "i2sbus: pcm name and id must be set!\n");
+               return -EINVAL;
+       }
+
+       list_for_each_entry(cii, &dev->codec_list, list) {
+               if (cii->codec_data == data)
+                       return -EALREADY;
+       }
+
+       if (!ci->transfers || !ci->transfers->formats
+           || !ci->transfers->rates || !ci->usable)
+               return -EINVAL;
+
+       /* we currently code the i2s transfer on the clock, and support only
+        * 32 and 64 */
+       if (ci->bus_factor != 32 && ci->bus_factor != 64)
+               return -EINVAL;
+
+       /* If you want to fix this, you need to keep track of what transport infos
+        * are to be used, which codecs they belong to, and then fix all the
+        * sysclock/busclock stuff above to depend on which is usable */
+       list_for_each_entry(cii, &dev->codec_list, list) {
+               if (cii->codec->sysclock_factor != ci->sysclock_factor) {
+                       printk(KERN_DEBUG
+                              "cannot yet handle multiple different sysclocks!\n");
+                       return -EINVAL;
+               }
+               if (cii->codec->bus_factor != ci->bus_factor) {
+                       printk(KERN_DEBUG
+                              "cannot yet handle multiple different bus clocks!\n");
+                       return -EINVAL;
+               }
+       }
+
+       tmp = ci->transfers;
+       while (tmp->formats && tmp->rates) {
+               if (tmp->transfer_in)
+                       in = 1;
+               else
+                       out = 1;
+               tmp++;
+       }
+
+       cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL);
+       if (!cii) {
+               printk(KERN_DEBUG "i2sbus: failed to allocate cii\n");
+               return -ENOMEM;
+       }
+
+       /* use the private data to point to the codec info */
+       cii->sdev = soundbus_dev_get(dev);
+       cii->codec = ci;
+       cii->codec_data = data;
+
+       if (!cii->sdev) {
+               printk(KERN_DEBUG
+                      "i2sbus: failed to get soundbus dev reference\n");
+               kfree(cii);
+               return -ENODEV;
+       }
+
+       if (!try_module_get(THIS_MODULE)) {
+               printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
+               soundbus_dev_put(dev);
+               kfree(cii);
+               return -EBUSY;
+       }
+
+       if (!try_module_get(ci->owner)) {
+               printk(KERN_DEBUG
+                      "i2sbus: failed to get module reference to codec owner!\n");
+               module_put(THIS_MODULE);
+               soundbus_dev_put(dev);
+               kfree(cii);
+               return -EBUSY;
+       }
+
+       if (!dev->pcm) {
+               err = snd_pcm_new(card,
+                                 dev->pcmname,
+                                 dev->pcmid,
+                                 0,
+                                 0,
+                                 &dev->pcm);
+               if (err) {
+                       printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
+                       kfree(cii);
+                       module_put(ci->owner);
+                       soundbus_dev_put(dev);
+                       module_put(THIS_MODULE);
+                       return err;
+               }
+       }
+
+       /* ALSA yet again sucks.
+        * If it is ever fixed, remove this line. See below. */
+       out = in = 1;
+
+       if (!i2sdev->out.created && out) {
+               if (dev->pcm->card != card) {
+                       /* eh? */
+                       printk(KERN_ERR
+                              "Can't attach same bus to different cards!\n");
+                       module_put(ci->owner);
+                       kfree(cii);
+                       soundbus_dev_put(dev);
+                       module_put(THIS_MODULE);
+                       return -EINVAL;
+               }
+               if ((err =
+                    snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) {
+                       module_put(ci->owner);
+                       kfree(cii);
+                       soundbus_dev_put(dev);
+                       module_put(THIS_MODULE);
+                       return err;
+               }
+               snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                               &i2sbus_playback_ops);
+               i2sdev->out.created = 1;
+       }
+
+       if (!i2sdev->in.created && in) {
+               if (dev->pcm->card != card) {
+                       printk(KERN_ERR
+                              "Can't attach same bus to different cards!\n");
+                       module_put(ci->owner);
+                       kfree(cii);
+                       soundbus_dev_put(dev);
+                       module_put(THIS_MODULE);
+                       return -EINVAL;
+               }
+               if ((err =
+                    snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) {
+                       module_put(ci->owner);
+                       kfree(cii);
+                       soundbus_dev_put(dev);
+                       module_put(THIS_MODULE);
+                       return err;
+               }
+               snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
+                               &i2sbus_record_ops);
+               i2sdev->in.created = 1;
+       }
+
+       /* so we have to register the pcm after adding any substream
+        * to it because alsa doesn't create the devices for the
+        * substreams when we add them later.
+        * Therefore, force in and out on both busses (above) and
+        * register the pcm now instead of just after creating it.
+        */
+       err = snd_device_register(card, dev->pcm);
+       if (err) {
+               printk(KERN_ERR "i2sbus: error registering new pcm\n");
+               module_put(ci->owner);
+               kfree(cii);
+               soundbus_dev_put(dev);
+               module_put(THIS_MODULE);
+               return err;
+       }
+       /* no errors any more, so let's add this to our list */
+       list_add(&cii->list, &dev->codec_list);
+
+       dev->pcm->private_data = i2sdev;
+       dev->pcm->private_free = i2sbus_private_free;
+
+       /* well, we really should support scatter/gather DMA */
+       snd_pcm_lib_preallocate_pages_for_all(
+               dev->pcm, SNDRV_DMA_TYPE_DEV,
+               snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)),
+               64 * 1024, 64 * 1024);
+
+       return 0;
+}
+
+void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)
+{
+       struct codec_info_item *cii = NULL, *i;
+
+       list_for_each_entry(i, &dev->codec_list, list) {
+               if (i->codec_data == data) {
+                       cii = i;
+                       break;
+               }
+       }
+       if (cii) {
+               list_del(&cii->list);
+               module_put(cii->codec->owner);
+               kfree(cii);
+       }
+       /* no more codecs, but still a pcm? */
+       if (list_empty(&dev->codec_list) && dev->pcm) {
+               /* the actual cleanup is done by the callback above! */
+               snd_device_free(dev->pcm->card, dev->pcm);
+       }
+}
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
new file mode 100644 (file)
index 0000000..cfa5162
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * i2sbus driver -- private definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __I2SBUS_H
+#define __I2SBUS_H
+#include <asm/dbdma.h>
+#include <linux/interrupt.h>
+#include <sound/pcm.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <asm/prom.h>
+#include "i2sbus-interface.h"
+#include "i2sbus-control.h"
+#include "../soundbus.h"
+
+struct i2sbus_control {
+       volatile struct i2s_control_regs __iomem *controlregs;
+       struct resource rsrc;
+       struct list_head list;
+};
+
+#define MAX_DBDMA_COMMANDS     32
+
+struct dbdma_command_mem {
+       dma_addr_t bus_addr;
+       dma_addr_t bus_cmd_start;
+       struct dbdma_cmd *cmds;
+       void *space;
+       int size;
+       u32 running:1;
+};
+
+struct pcm_info {
+       u32 created:1, /* has this direction been created with alsa? */
+           active:1;  /* is this stream active? */
+       /* runtime information */
+       struct snd_pcm_substream *substream;
+       int current_period;
+       u32 frame_count;
+       struct dbdma_command_mem dbdma_ring;
+       volatile struct dbdma_regs __iomem *dbdma;
+};
+
+struct i2sbus_dev {
+       struct soundbus_dev sound;
+       struct macio_dev *macio;
+       struct i2sbus_control *control;
+       volatile struct i2s_interface_regs __iomem *intfregs;
+
+       struct resource resources[3];
+       struct resource *allocated_resource[3];
+       int interrupts[3];
+       char rnames[3][32];
+
+       /* info about currently active substreams */
+       struct pcm_info out, in;
+       snd_pcm_format_t format;
+       unsigned int rate;
+
+       /* list for a single controller */
+       struct list_head item;
+       /* number of bus on controller */
+       int bus_number;
+       /* for use by control layer */
+       struct pmf_function *enable,
+                           *cell_enable,
+                           *cell_disable,
+                           *clock_enable,
+                           *clock_disable;
+
+       /* locks */
+       /* spinlock for low-level interrupt locking */
+       spinlock_t low_lock;
+       /* mutex for high-level consistency */
+       struct mutex lock;
+};
+
+#define soundbus_dev_to_i2sbus_dev(sdev) \
+               container_of(sdev, struct i2sbus_dev, sound)
+
+/* pcm specific functions */
+extern int
+i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
+                   struct codec_info *ci, void *data);
+extern void
+i2sbus_detach_codec(struct soundbus_dev *dev, void *data);
+extern irqreturn_t
+i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs);
+extern irqreturn_t
+i2sbus_rx_intr(int irq, void *devid, struct pt_regs *regs);
+
+/* control specific functions */
+extern int i2sbus_control_init(struct macio_dev* dev,
+                              struct i2sbus_control **c);
+extern void i2sbus_control_destroy(struct i2sbus_control *c);
+extern int i2sbus_control_add_dev(struct i2sbus_control *c,
+                                 struct i2sbus_dev *i2sdev);
+extern void i2sbus_control_remove_dev(struct i2sbus_control *c,
+                                     struct i2sbus_dev *i2sdev);
+extern int i2sbus_control_enable(struct i2sbus_control *c,
+                                struct i2sbus_dev *i2sdev);
+extern int i2sbus_control_cell(struct i2sbus_control *c,
+                              struct i2sbus_dev *i2sdev,
+                              int enable);
+extern int i2sbus_control_clock(struct i2sbus_control *c,
+                               struct i2sbus_dev *i2sdev,
+                               int enable);
+#endif /* __I2SBUS_H */
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h
new file mode 100644 (file)
index 0000000..5c27297
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * soundbus generic definitions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ */
+#ifndef __SOUNDBUS_H
+#define __SOUNDBUS_H
+
+#include <asm/of_device.h>
+#include <sound/pcm.h>
+#include <linux/list.h>
+
+
+/* When switching from master to slave or the other way around,
+ * you don't want to have the codec chip acting as clock source
+ * while the bus still is.
+ * More importantly, while switch from slave to master, you need
+ * to turn off the chip's master function first, but then there's
+ * no clock for a while and other chips might reset, so we notify
+ * their drivers after having switched.
+ * The constants here are codec-point of view, so when we switch
+ * the soundbus to master we tell the codec we're going to switch
+ * and give it CLOCK_SWITCH_PREPARE_SLAVE!
+ */
+enum clock_switch {
+       CLOCK_SWITCH_PREPARE_SLAVE,
+       CLOCK_SWITCH_PREPARE_MASTER,
+       CLOCK_SWITCH_SLAVE,
+       CLOCK_SWITCH_MASTER,
+       CLOCK_SWITCH_NOTIFY,
+};
+
+/* information on a transfer the codec can take */
+struct transfer_info {
+       u64 formats;            /* SNDRV_PCM_FMTBIT_* */
+       unsigned int rates;     /* SNDRV_PCM_RATE_* */
+       /* flags */
+       u32 transfer_in:1, /* input = 1, output = 0 */
+           must_be_clock_source:1;
+       /* for codecs to distinguish among their TIs */
+       int tag;
+};
+
+struct codec_info_item {
+       struct codec_info *codec;
+       void *codec_data;
+       struct soundbus_dev *sdev;
+       /* internal, to be used by the soundbus provider */
+       struct list_head list;
+};
+
+/* for prepare, where the codecs need to know
+ * what we're going to drive the bus with */
+struct bus_info {
+       /* see below */
+       int sysclock_factor;
+       int bus_factor;
+};
+
+/* information on the codec itself, plus function pointers */
+struct codec_info {
+       /* the module this lives in */
+       struct module *owner;
+
+       /* supported transfer possibilities, array terminated by
+        * formats or rates being 0. */
+       struct transfer_info *transfers;
+
+       /* Master clock speed factor
+        * to be used (master clock speed = sysclock_factor * sampling freq)
+        * Unused if the soundbus provider has no such notion.
+        */
+       int sysclock_factor;
+
+       /* Bus factor, bus clock speed = bus_factor * sampling freq)
+        * Unused if the soundbus provider has no such notion.
+        */
+       int bus_factor;
+
+       /* operations */
+       /* clock switching, see above */
+       int (*switch_clock)(struct codec_info_item *cii,
+                           enum clock_switch clock);
+
+       /* called for each transfer_info when the user
+        * opens the pcm device to determine what the
+        * hardware can support at this point in time.
+        * That can depend on other user-switchable controls.
+        * Return 1 if usable, 0 if not.
+        * out points to another instance of a transfer_info
+        * which is initialised to the values in *ti, and
+        * it's format and rate values can be modified by
+        * the callback if it is necessary to further restrict
+        * the formats that can be used at the moment, for
+        * example when one codec has multiple logical codec
+        * info structs for multiple inputs.
+        */
+       int (*usable)(struct codec_info_item *cii,
+                     struct transfer_info *ti,
+                     struct transfer_info *out);
+
+       /* called when pcm stream is opened, probably not implemented
+        * most of the time since it isn't too useful */
+       int (*open)(struct codec_info_item *cii,
+                   struct snd_pcm_substream *substream);
+
+       /* called when the pcm stream is closed, at this point
+        * the user choices can all be unlocked (see below) */
+       int (*close)(struct codec_info_item *cii,
+                    struct snd_pcm_substream *substream);
+
+       /* if the codec must forbid some user choices because
+        * they are not valid with the substream/transfer info,
+        * it must do so here. Example: no digital output for
+        * incompatible framerate, say 8KHz, on Onyx.
+        * If the selected stuff in the substream is NOT
+        * compatible, you have to reject this call! */
+       int (*prepare)(struct codec_info_item *cii,
+                      struct bus_info *bi,
+                      struct snd_pcm_substream *substream);
+
+       /* start() is called before data is pushed to the codec.
+        * Note that start() must be atomic! */
+       int (*start)(struct codec_info_item *cii,
+                    struct snd_pcm_substream *substream);
+
+       /* stop() is called after data is no longer pushed to the codec.
+        * Note that stop() must be atomic! */
+       int (*stop)(struct codec_info_item *cii,
+                   struct snd_pcm_substream *substream);
+
+       int (*suspend)(struct codec_info_item *cii, pm_message_t state);
+       int (*resume)(struct codec_info_item *cii);
+};
+
+/* information on a soundbus device */
+struct soundbus_dev {
+       /* the bus it belongs to */
+       struct list_head onbuslist;
+
+       /* the of device it represents */
+       struct of_device ofdev;
+
+       /* what modules go by */
+       char modalias[32];
+
+       /* These fields must be before attach_codec can be called.
+        * They should be set by the owner of the alsa card object
+        * that is needed, and whoever sets them must make sure
+        * that they are unique within that alsa card object. */
+       char *pcmname;
+       int pcmid;
+
+       /* this is assigned by the soundbus provider in attach_codec */
+       struct snd_pcm *pcm;
+
+       /* operations */
+       /* attach a codec to this soundbus, give the alsa
+        * card object the PCMs for this soundbus should be in.
+        * The 'data' pointer must be unique, it is used as the
+        * key for detach_codec(). */
+       int (*attach_codec)(struct soundbus_dev *dev, struct snd_card *card,
+                           struct codec_info *ci, void *data);
+       void (*detach_codec)(struct soundbus_dev *dev, void *data);
+       /* TODO: suspend/resume */
+
+       /* private for the soundbus provider */
+       struct list_head codec_list;
+       u32 have_out:1, have_in:1;
+};
+#define to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev.dev)
+#define of_to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev)
+
+extern int soundbus_add_one(struct soundbus_dev *dev);
+extern void soundbus_remove_one(struct soundbus_dev *dev);
+
+extern struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev);
+extern void soundbus_dev_put(struct soundbus_dev *dev);
+
+struct soundbus_driver {
+       char *name;
+       struct module *owner;
+
+       /* we don't implement any matching at all */
+
+       int     (*probe)(struct soundbus_dev* dev);
+       int     (*remove)(struct soundbus_dev* dev);
+
+       int     (*suspend)(struct soundbus_dev* dev, pm_message_t state);
+       int     (*resume)(struct soundbus_dev* dev);
+       int     (*shutdown)(struct soundbus_dev* dev);
+
+       struct device_driver driver;
+};
+#define to_soundbus_driver(drv) container_of(drv,struct soundbus_driver, driver)
+
+extern int soundbus_register_driver(struct soundbus_driver *drv);
+extern void soundbus_unregister_driver(struct soundbus_driver *drv);
+
+#endif /* __SOUNDBUS_H */
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
new file mode 100644 (file)
index 0000000..d31f814
--- /dev/null
@@ -0,0 +1,43 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+/* FIX UP */
+#include "soundbus.h"
+
+#define soundbus_config_of_attr(field, format_string)                  \
+static ssize_t                                                         \
+field##_show (struct device *dev, struct device_attribute *attr,       \
+              char *buf)                                               \
+{                                                                      \
+       struct soundbus_dev *mdev = to_soundbus_device (dev);           \
+       return sprintf (buf, format_string, mdev->ofdev.node->field);   \
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct soundbus_dev *sdev = to_soundbus_device(dev);
+       struct of_device *of = &sdev->ofdev;
+       int length;
+
+       if (*sdev->modalias) {
+               strlcpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1);
+               strcat(buf, "\n");
+               length = strlen(buf);
+       } else {
+               length = sprintf(buf, "of:N%sT%s\n",
+                                of->node->name, of->node->type);
+       }
+
+       return length;
+}
+
+soundbus_config_of_attr (name, "%s\n");
+soundbus_config_of_attr (type, "%s\n");
+
+struct device_attribute soundbus_dev_attrs[] = {
+       __ATTR_RO(name),
+       __ATTR_RO(type),
+       __ATTR_RO(modalias),
+       __ATTR_NULL
+};
index 13057d92f08afb0a8888f5fece7f5d9952790ad4..b88fb0c5a68a4869b3212f4815b7ff9ed1c048cd 100644 (file)
@@ -112,7 +112,7 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA");
 MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}");
 
-static char *id = NULL;        /* ID for this card */
+static char *id;       /* ID for this card */
 
 module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
@@ -984,11 +984,15 @@ static int __init sa11xx_uda1341_init(void)
        if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)
                return err;
        device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);
-       if (IS_ERR(device)) {
-               platform_driver_unregister(&sa11xx_uda1341_driver);
-               return PTR_ERR(device);
-       }
-       return 0;
+       if (!IS_ERR(device)) {
+               if (platform_get_drvdata(device))
+                       return 0;
+               platform_device_unregister(device);
+               err = -ENODEV
+       } else
+               err = PTR_ERR(device);
+       platform_driver_unregister(&sa11xx_uda1341_driver);
+       return err;
 }
 
 static void __exit sa11xx_uda1341_exit(void)
index 22565c9b9603ea3b43b6794ef7f09b724d338122..bb397eaa718793cb977687628eed02a9d4477907 100644 (file)
@@ -176,6 +176,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
        read_unlock(&card->ctl_files_rwlock);
 }
 
+EXPORT_SYMBOL(snd_ctl_notify);
+
 /**
  * snd_ctl_new - create a control instance from the template
  * @control: the control template
@@ -204,6 +206,8 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce
        return kctl;
 }
 
+EXPORT_SYMBOL(snd_ctl_new);
+
 /**
  * snd_ctl_new1 - create a control instance from the template
  * @ncontrol: the initialization record
@@ -242,6 +246,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
        return snd_ctl_new(&kctl, access);
 }
 
+EXPORT_SYMBOL(snd_ctl_new1);
+
 /**
  * snd_ctl_free_one - release the control instance
  * @kcontrol: the control instance
@@ -259,6 +265,8 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
        }
 }
 
+EXPORT_SYMBOL(snd_ctl_free_one);
+
 static unsigned int snd_ctl_hole_check(struct snd_card *card,
                                       unsigned int count)
 {
@@ -347,6 +355,8 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
        return err;
 }
 
+EXPORT_SYMBOL(snd_ctl_add);
+
 /**
  * snd_ctl_remove - remove the control from the card and release it
  * @card: the card instance
@@ -373,6 +383,8 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_ctl_remove);
+
 /**
  * snd_ctl_remove_id - remove the control of the given id and release it
  * @card: the card instance
@@ -399,6 +411,8 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
        return ret;
 }
 
+EXPORT_SYMBOL(snd_ctl_remove_id);
+
 /**
  * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it
  * @file: active control handle
@@ -461,6 +475,8 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_ctl_rename_id);
+
 /**
  * snd_ctl_find_numid - find the control instance with the given number-id
  * @card: the card instance
@@ -487,6 +503,8 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi
        return NULL;
 }
 
+EXPORT_SYMBOL(snd_ctl_find_numid);
+
 /**
  * snd_ctl_find_id - find the control instance with the given id
  * @card: the card instance
@@ -527,6 +545,8 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
        return NULL;
 }
 
+EXPORT_SYMBOL(snd_ctl_find_id);
+
 static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
                             unsigned int cmd, void __user *arg)
 {
@@ -704,6 +724,8 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control)
        return result;
 }
 
+EXPORT_SYMBOL(snd_ctl_elem_read);
+
 static int snd_ctl_elem_read_user(struct snd_card *card,
                                  struct snd_ctl_elem_value __user *_control)
 {
@@ -767,6 +789,8 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
        return result;
 }
 
+EXPORT_SYMBOL(snd_ctl_elem_write);
+
 static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
                                   struct snd_ctl_elem_value __user *_control)
 {
@@ -1199,11 +1223,15 @@ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
        return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
 }
 
+EXPORT_SYMBOL(snd_ctl_register_ioctl);
+
 #ifdef CONFIG_COMPAT
 int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
 {
        return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
 }
+
+EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
 #endif
 
 /*
@@ -1236,12 +1264,15 @@ int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
        return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
 }
 
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
+
 #ifdef CONFIG_COMPAT
 int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
 {
        return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
 }
 
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
 #endif
 
 static int snd_ctl_fasync(int fd, struct file * file, int on)
index b1cf6ec567848bd4620e22c8224adbf687489b84..6ce4da4a1081995317c79523c22bfefd63786529 100644 (file)
@@ -63,6 +63,8 @@ int snd_device_new(struct snd_card *card, snd_device_type_t type,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_device_new);
+
 /**
  * snd_device_free - release the device from the card
  * @card: the card instance
@@ -107,6 +109,8 @@ int snd_device_free(struct snd_card *card, void *device_data)
        return -ENXIO;
 }
 
+EXPORT_SYMBOL(snd_device_free);
+
 /**
  * snd_device_disconnect - disconnect the device
  * @card: the card instance
@@ -182,6 +186,8 @@ int snd_device_register(struct snd_card *card, void *device_data)
        return -ENXIO;
 }
 
+EXPORT_SYMBOL(snd_device_register);
+
 /*
  * register all the devices on the card.
  * called from init.c
index 2524e66eccdd28e0f747eb6d4ac09cba94e9f8bf..8bd0dcc93eba98f787664085bf9734f2ed89f05d 100644 (file)
@@ -486,7 +486,6 @@ static void __init snd_hwdep_proc_init(void)
        struct snd_info_entry *entry;
 
        if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) {
-               entry->c.text.read_size = PAGE_SIZE;
                entry->c.text.read = snd_hwdep_proc_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
index 2582b74d319953ebd0cb95d46f36d7e044e520fe..10c1772bf3ea3dbe9ff06960f945d06457112a35 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/vmalloc.h>
 #include <linux/time.h>
 #include <linux/smp_lock.h>
 #include <linux/string.h>
@@ -82,6 +81,24 @@ static int snd_info_version_init(void);
 static int snd_info_version_done(void);
 
 
+/* resize the proc r/w buffer */
+static int resize_info_buffer(struct snd_info_buffer *buffer,
+                             unsigned int nsize)
+{
+       char *nbuf;
+
+       nsize = PAGE_ALIGN(nsize);
+       nbuf = kmalloc(nsize, GFP_KERNEL);
+       if (! nbuf)
+               return -ENOMEM;
+
+       memcpy(nbuf, buffer->buffer, buffer->len);
+       kfree(buffer->buffer);
+       buffer->buffer = nbuf;
+       buffer->len = nsize;
+       return 0;
+}
+
 /**
  * snd_iprintf - printf on the procfs buffer
  * @buffer: the procfs buffer
@@ -95,30 +112,43 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...)
 {
        va_list args;
        int len, res;
+       int err = 0;
 
+       might_sleep();
        if (buffer->stop || buffer->error)
                return 0;
        len = buffer->len - buffer->size;
        va_start(args, fmt);
-       res = vsnprintf(buffer->curr, len, fmt, args);
-       va_end(args);
-       if (res >= len) {
-               buffer->stop = 1;
-               return 0;
+       for (;;) {
+               res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args);
+               if (res < len)
+                       break;
+               err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
+               if (err < 0)
+                       break;
+               len = buffer->len - buffer->size;
        }
+       va_end(args);
+
+       if (err < 0)
+               return err;
        buffer->curr += res;
        buffer->size += res;
        return res;
 }
 
+EXPORT_SYMBOL(snd_iprintf);
+
 /*
 
  */
 
-static struct proc_dir_entry *snd_proc_root = NULL;
-struct snd_info_entry *snd_seq_root = NULL;
+static struct proc_dir_entry *snd_proc_root;
+struct snd_info_entry *snd_seq_root;
+EXPORT_SYMBOL(snd_seq_root);
+
 #ifdef CONFIG_SND_OSSEMUL
-struct snd_info_entry *snd_oss_root = NULL;
+struct snd_info_entry *snd_oss_root;
 #endif
 
 static inline void snd_info_entry_prepare(struct proc_dir_entry *de)
@@ -221,7 +251,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
        struct snd_info_private_data *data;
        struct snd_info_entry *entry;
        struct snd_info_buffer *buf;
-       size_t size = 0;
+       ssize_t size = 0;
        loff_t pos;
 
        data = file->private_data;
@@ -237,14 +267,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
                buf = data->wbuffer;
                if (buf == NULL)
                        return -EIO;
-               if (pos >= buf->len)
-                       return -ENOMEM;
-               size = buf->len - pos;
-               size = min(count, size);
-               if (copy_from_user(buf->buffer + pos, buffer, size))
+               mutex_lock(&entry->access);
+               if (pos + count >= buf->len) {
+                       if (resize_info_buffer(buf, pos + count)) {
+                               mutex_unlock(&entry->access);
+                               return -ENOMEM;
+                       }
+               }
+               if (copy_from_user(buf->buffer + pos, buffer, count)) {
+                       mutex_unlock(&entry->access);
                        return -EFAULT;
-               if ((long)buf->size < pos + size)
-                       buf->size = pos + size;
+               }
+               buf->size = pos + count;
+               mutex_unlock(&entry->access);
+               size = count;
                break;
        case SNDRV_INFO_CONTENT_DATA:
                if (entry->c.ops->write)
@@ -279,18 +315,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
        }
        mode = file->f_flags & O_ACCMODE;
        if (mode == O_RDONLY || mode == O_RDWR) {
-               if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
-                    !entry->c.text.read_size) ||
-                   (entry->content == SNDRV_INFO_CONTENT_DATA &&
+               if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
                     entry->c.ops->read == NULL)) {
                        err = -ENODEV;
                        goto __error;
                }
        }
        if (mode == O_WRONLY || mode == O_RDWR) {
-               if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
-                    !entry->c.text.write_size) ||
-                   (entry->content == SNDRV_INFO_CONTENT_DATA &&
+               if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
                     entry->c.ops->write == NULL)) {
                        err = -ENODEV;
                        goto __error;
@@ -306,49 +338,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
        case SNDRV_INFO_CONTENT_TEXT:
                if (mode == O_RDONLY || mode == O_RDWR) {
                        buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-                       if (buffer == NULL) {
-                               kfree(data);
-                               err = -ENOMEM;
-                               goto __error;
-                       }
-                       buffer->len = (entry->c.text.read_size +
-                                     (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-                       buffer->buffer = vmalloc(buffer->len);
-                       if (buffer->buffer == NULL) {
-                               kfree(buffer);
-                               kfree(data);
-                               err = -ENOMEM;
-                               goto __error;
-                       }
-                       buffer->curr = buffer->buffer;
+                       if (buffer == NULL)
+                               goto __nomem;
                        data->rbuffer = buffer;
+                       buffer->len = PAGE_SIZE;
+                       buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
+                       if (buffer->buffer == NULL)
+                               goto __nomem;
                }
                if (mode == O_WRONLY || mode == O_RDWR) {
                        buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-                       if (buffer == NULL) {
-                               if (mode == O_RDWR) {
-                                       vfree(data->rbuffer->buffer);
-                                       kfree(data->rbuffer);
-                               }
-                               kfree(data);
-                               err = -ENOMEM;
-                               goto __error;
-                       }
-                       buffer->len = (entry->c.text.write_size +
-                                     (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
-                       buffer->buffer = vmalloc(buffer->len);
-                       if (buffer->buffer == NULL) {
-                               if (mode == O_RDWR) {
-                                       vfree(data->rbuffer->buffer);
-                                       kfree(data->rbuffer);
-                               }
-                               kfree(buffer);
-                               kfree(data);
-                               err = -ENOMEM;
-                               goto __error;
-                       }
-                       buffer->curr = buffer->buffer;
+                       if (buffer == NULL)
+                               goto __nomem;
                        data->wbuffer = buffer;
+                       buffer->len = PAGE_SIZE;
+                       buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
+                       if (buffer->buffer == NULL)
+                               goto __nomem;
                }
                break;
        case SNDRV_INFO_CONTENT_DATA:   /* data */
@@ -373,6 +379,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
        }
        return 0;
 
+ __nomem:
+       if (data->rbuffer) {
+               kfree(data->rbuffer->buffer);
+               kfree(data->rbuffer);
+       }
+       if (data->wbuffer) {
+               kfree(data->wbuffer->buffer);
+               kfree(data->wbuffer);
+       }
+       kfree(data);
+       err = -ENOMEM;
       __error:
        module_put(entry->module);
       __error1:
@@ -391,11 +408,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
        entry = data->entry;
        switch (entry->content) {
        case SNDRV_INFO_CONTENT_TEXT:
-               if (mode == O_RDONLY || mode == O_RDWR) {
-                       vfree(data->rbuffer->buffer);
+               if (data->rbuffer) {
+                       kfree(data->rbuffer->buffer);
                        kfree(data->rbuffer);
                }
-               if (mode == O_WRONLY || mode == O_RDWR) {
+               if (data->wbuffer) {
                        if (entry->c.text.write) {
                                entry->c.text.write(entry, data->wbuffer);
                                if (data->wbuffer->error) {
@@ -404,7 +421,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
                                                data->wbuffer->error);
                                }
                        }
-                       vfree(data->wbuffer->buffer);
+                       kfree(data->wbuffer->buffer);
                        kfree(data->wbuffer);
                }
                break;
@@ -664,29 +681,29 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
        if (len <= 0 || buffer->stop || buffer->error)
                return 1;
        while (--len > 0) {
-               c = *buffer->curr++;
+               c = buffer->buffer[buffer->curr++];
                if (c == '\n') {
-                       if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
+                       if (buffer->curr >= buffer->size)
                                buffer->stop = 1;
-                       }
                        break;
                }
                *line++ = c;
-               if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
+               if (buffer->curr >= buffer->size) {
                        buffer->stop = 1;
                        break;
                }
        }
        while (c != '\n' && !buffer->stop) {
-               c = *buffer->curr++;
-               if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
+               c = buffer->buffer[buffer->curr++];
+               if (buffer->curr >= buffer->size)
                        buffer->stop = 1;
-               }
        }
        *line = '\0';
        return 0;
 }
 
+EXPORT_SYMBOL(snd_info_get_line);
+
 /**
  * snd_info_get_str - parse a string token
  * @dest: the buffer to store the string token
@@ -723,6 +740,8 @@ char *snd_info_get_str(char *dest, char *src, int len)
        return src;
 }
 
+EXPORT_SYMBOL(snd_info_get_str);
+
 /**
  * snd_info_create_entry - create an info entry
  * @name: the proc file name
@@ -774,6 +793,8 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module,
        return entry;
 }
 
+EXPORT_SYMBOL(snd_info_create_module_entry);
+
 /**
  * snd_info_create_card_entry - create an info entry for the given card
  * @card: the card instance
@@ -797,6 +818,8 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
        return entry;
 }
 
+EXPORT_SYMBOL(snd_info_create_card_entry);
+
 static int snd_info_dev_free_entry(struct snd_device *device)
 {
        struct snd_info_entry *entry = device->device_data;
@@ -867,6 +890,8 @@ int snd_card_proc_new(struct snd_card *card, const char *name,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_card_proc_new);
+
 /**
  * snd_info_free_entry - release the info entry
  * @entry: the info entry
@@ -883,6 +908,8 @@ void snd_info_free_entry(struct snd_info_entry * entry)
        kfree(entry);
 }
 
+EXPORT_SYMBOL(snd_info_free_entry);
+
 /**
  * snd_info_register - register the info entry
  * @entry: the info entry
@@ -913,6 +940,8 @@ int snd_info_register(struct snd_info_entry * entry)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_info_register);
+
 /**
  * snd_info_unregister - de-register the info entry
  * @entry: the info entry
@@ -937,11 +966,13 @@ int snd_info_unregister(struct snd_info_entry * entry)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_info_unregister);
+
 /*
 
  */
 
-static struct snd_info_entry *snd_info_version_entry = NULL;
+static struct snd_info_entry *snd_info_version_entry;
 
 static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
@@ -958,7 +989,6 @@ static int __init snd_info_version_init(void)
        entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
        if (entry == NULL)
                return -ENOMEM;
-       entry->c.text.read_size = 256;
        entry->c.text.read = snd_info_version_read;
        if (snd_info_register(entry) < 0) {
                snd_info_free_entry(entry);
index f9ce854b3d114b441caa08525aff8643dd4b7fff..bb2c40d0ab66cd6f890ad86ac713246c561b3c7e 100644 (file)
@@ -64,6 +64,8 @@ int snd_oss_info_register(int dev, int num, char *string)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_oss_info_register);
+
 extern void snd_card_info_read_oss(struct snd_info_buffer *buffer);
 
 static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev)
@@ -117,7 +119,6 @@ int snd_info_minor_register(void)
 
        memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
        if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
-               entry->c.text.read_size = 2048;
                entry->c.text.read = snd_sndstat_proc_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
index 39ed2e5bb0af1b4a5c4320d7f14300f08bc40b8e..4d9258884e444c368be86da0c470a69726f2253d 100644 (file)
@@ -38,12 +38,15 @@ struct snd_shutdown_f_ops {
        struct snd_shutdown_f_ops *next;
 };
 
-unsigned int snd_cards_lock = 0;       /* locked for registering/using */
-struct snd_card *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
-DEFINE_RWLOCK(snd_card_rwlock);
+static unsigned int snd_cards_lock;    /* locked for registering/using */
+struct snd_card *snd_cards[SNDRV_CARDS];
+EXPORT_SYMBOL(snd_cards);
+
+static DEFINE_MUTEX(snd_card_mutex);
 
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
+EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
 #endif
 
 #ifdef CONFIG_PROC_FS
@@ -66,7 +69,6 @@ static inline int init_info_for_card(struct snd_card *card)
                snd_printd("unable to create card entry\n");
                return err;
        }
-       entry->c.text.read_size = PAGE_SIZE;
        entry->c.text.read = snd_card_id_read;
        if (snd_info_register(entry) < 0) {
                snd_info_free_entry(entry);
@@ -110,7 +112,7 @@ struct snd_card *snd_card_new(int idx, const char *xid,
                strlcpy(card->id, xid, sizeof(card->id));
        }
        err = 0;
-       write_lock(&snd_card_rwlock);
+       mutex_lock(&snd_card_mutex);
        if (idx < 0) {
                int idx2;
                for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
@@ -128,12 +130,12 @@ struct snd_card *snd_card_new(int idx, const char *xid,
        else
                err = -ENODEV;
        if (idx < 0 || err < 0) {
-               write_unlock(&snd_card_rwlock);
+               mutex_unlock(&snd_card_mutex);
                snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
                goto __error;
        }
        snd_cards_lock |= 1 << idx;             /* lock it */
-       write_unlock(&snd_card_rwlock);
+       mutex_unlock(&snd_card_mutex);
        card->number = idx;
        card->module = module;
        INIT_LIST_HEAD(&card->devices);
@@ -169,6 +171,19 @@ struct snd_card *snd_card_new(int idx, const char *xid,
        return NULL;
 }
 
+EXPORT_SYMBOL(snd_card_new);
+
+/* return non-zero if a card is already locked */
+int snd_card_locked(int card)
+{
+       int locked;
+
+       mutex_lock(&snd_card_mutex);
+       locked = snd_cards_lock & (1 << card);
+       mutex_unlock(&snd_card_mutex);
+       return locked;
+}
+
 static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
 {
        return -ENODEV;
@@ -236,9 +251,9 @@ int snd_card_disconnect(struct snd_card *card)
        spin_unlock(&card->files_lock);
 
        /* phase 1: disable fops (user space) operations for ALSA API */
-       write_lock(&snd_card_rwlock);
+       mutex_lock(&snd_card_mutex);
        snd_cards[card->number] = NULL;
-       write_unlock(&snd_card_rwlock);
+       mutex_unlock(&snd_card_mutex);
        
        /* phase 2: replace file->f_op with special dummy operations */
        
@@ -298,6 +313,8 @@ int snd_card_disconnect(struct snd_card *card)
        return 0;       
 }
 
+EXPORT_SYMBOL(snd_card_disconnect);
+
 /**
  *  snd_card_free - frees given soundcard structure
  *  @card: soundcard structure
@@ -315,9 +332,9 @@ int snd_card_free(struct snd_card *card)
 
        if (card == NULL)
                return -EINVAL;
-       write_lock(&snd_card_rwlock);
+       mutex_lock(&snd_card_mutex);
        snd_cards[card->number] = NULL;
-       write_unlock(&snd_card_rwlock);
+       mutex_unlock(&snd_card_mutex);
 
 #ifdef CONFIG_PM
        wake_up(&card->power_sleep);
@@ -353,13 +370,15 @@ int snd_card_free(struct snd_card *card)
                card->s_f_ops = s_f_ops->next;
                kfree(s_f_ops);
        }
-       write_lock(&snd_card_rwlock);
+       mutex_lock(&snd_card_mutex);
        snd_cards_lock &= ~(1 << card->number);
-       write_unlock(&snd_card_rwlock);
+       mutex_unlock(&snd_card_mutex);
        kfree(card);
        return 0;
 }
 
+EXPORT_SYMBOL(snd_card_free);
+
 static void snd_card_free_thread(void * __card)
 {
        struct snd_card *card = __card;
@@ -405,6 +424,8 @@ int snd_card_free_in_thread(struct snd_card *card)
        return -EFAULT;
 }
 
+EXPORT_SYMBOL(snd_card_free_in_thread);
+
 static void choose_default_id(struct snd_card *card)
 {
        int i, len, idx_flag = 0, loops = SNDRV_CARDS;
@@ -487,16 +508,16 @@ int snd_card_register(struct snd_card *card)
        snd_assert(card != NULL, return -EINVAL);
        if ((err = snd_device_register_all(card)) < 0)
                return err;
-       write_lock(&snd_card_rwlock);
+       mutex_lock(&snd_card_mutex);
        if (snd_cards[card->number]) {
                /* already registered */
-               write_unlock(&snd_card_rwlock);
+               mutex_unlock(&snd_card_mutex);
                return 0;
        }
        if (card->id[0] == '\0')
                choose_default_id(card);
        snd_cards[card->number] = card;
-       write_unlock(&snd_card_rwlock);
+       mutex_unlock(&snd_card_mutex);
        init_info_for_card(card);
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
        if (snd_mixer_oss_notify_callback)
@@ -505,8 +526,10 @@ int snd_card_register(struct snd_card *card)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_card_register);
+
 #ifdef CONFIG_PROC_FS
-static struct snd_info_entry *snd_card_info_entry = NULL;
+static struct snd_info_entry *snd_card_info_entry;
 
 static void snd_card_info_read(struct snd_info_entry *entry,
                               struct snd_info_buffer *buffer)
@@ -515,7 +538,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
        struct snd_card *card;
 
        for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
-               read_lock(&snd_card_rwlock);
+               mutex_lock(&snd_card_mutex);
                if ((card = snd_cards[idx]) != NULL) {
                        count++;
                        snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n",
@@ -526,7 +549,7 @@ static void snd_card_info_read(struct snd_info_entry *entry,
                        snd_iprintf(buffer, "                      %s\n",
                                        card->longname);
                }
-               read_unlock(&snd_card_rwlock);
+               mutex_unlock(&snd_card_mutex);
        }
        if (!count)
                snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -540,12 +563,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
        struct snd_card *card;
 
        for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
-               read_lock(&snd_card_rwlock);
+               mutex_lock(&snd_card_mutex);
                if ((card = snd_cards[idx]) != NULL) {
                        count++;
                        snd_iprintf(buffer, "%s\n", card->longname);
                }
-               read_unlock(&snd_card_rwlock);
+               mutex_unlock(&snd_card_mutex);
        }
        if (!count) {
                snd_iprintf(buffer, "--- no soundcards ---\n");
@@ -563,11 +586,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
        struct snd_card *card;
 
        for (idx = 0; idx < SNDRV_CARDS; idx++) {
-               read_lock(&snd_card_rwlock);
+               mutex_lock(&snd_card_mutex);
                if ((card = snd_cards[idx]) != NULL)
                        snd_iprintf(buffer, "%2i %s\n",
                                    idx, card->module->name);
-               read_unlock(&snd_card_rwlock);
+               mutex_unlock(&snd_card_mutex);
        }
 }
 #endif
@@ -579,7 +602,6 @@ int __init snd_card_info_init(void)
        entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL);
        if (! entry)
                return -ENOMEM;
-       entry->c.text.read_size = PAGE_SIZE;
        entry->c.text.read = snd_card_info_read;
        if (snd_info_register(entry) < 0) {
                snd_info_free_entry(entry);
@@ -590,7 +612,6 @@ int __init snd_card_info_init(void)
 #ifdef MODULE
        entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
        if (entry) {
-               entry->c.text.read_size = PAGE_SIZE;
                entry->c.text.read = snd_card_module_info_read;
                if (snd_info_register(entry) < 0)
                        snd_info_free_entry(entry);
@@ -644,6 +665,8 @@ int snd_component_add(struct snd_card *card, const char *component)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_component_add);
+
 /**
  *  snd_card_file_add - add the file to the file list of the card
  *  @card: soundcard structure
@@ -676,6 +699,8 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_card_file_add);
+
 /**
  *  snd_card_file_remove - remove the file from the file list
  *  @card: soundcard structure
@@ -717,6 +742,8 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_card_file_remove);
+
 #ifdef CONFIG_PM
 /**
  *  snd_power_wait - wait until the power-state is changed.
@@ -753,4 +780,5 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
        return result;
 }
 
+EXPORT_SYMBOL(snd_power_wait);
 #endif /* CONFIG_PM */
index 1a378951da5b862bf0685e0ce5a138a3859fd757..d52398727f0abd4cc32b1b16434726644d42a6f8 100644 (file)
@@ -56,6 +56,8 @@ void snd_dma_program(unsigned long dma,
        release_dma_lock(flags);
 }
 
+EXPORT_SYMBOL(snd_dma_program);
+
 /**
  * snd_dma_disable - stop the ISA DMA transfer
  * @dma: the dma number
@@ -72,6 +74,8 @@ void snd_dma_disable(unsigned long dma)
        release_dma_lock(flags);
 }
 
+EXPORT_SYMBOL(snd_dma_disable);
+
 /**
  * snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes
  * @dma: the dma number
@@ -101,3 +105,5 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
        else
                return size - result;
 }
+
+EXPORT_SYMBOL(snd_dma_pointer);
index 862d62d2e144f107a76d9c2b0af93e4c95e1096d..fe59850be868d4167617f326307520203ca3dc20 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -55,6 +56,8 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size
 #endif
 }
 
+EXPORT_SYMBOL(copy_to_user_fromio);
+
 /**
  * copy_from_user_toio - copy data from user-space to mmio-space
  * @dst: the destination pointer on mmio-space
@@ -85,3 +88,5 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
        return 0;
 #endif
 }
+
+EXPORT_SYMBOL(copy_from_user_toio);
index b53e563c09e60d0e16f843bb034d0842df0cc432..03fc711f4127a5d361cc9b349ef7258c224136d9 100644 (file)
@@ -34,6 +34,8 @@ void release_and_free_resource(struct resource *res)
        }
 }
 
+EXPORT_SYMBOL(release_and_free_resource);
+
 #ifdef CONFIG_SND_VERBOSE_PRINTK
 void snd_verbose_printk(const char *file, int line, const char *format, ...)
 {
@@ -51,6 +53,8 @@ void snd_verbose_printk(const char *file, int line, const char *format, ...)
        vprintk(format, args);
        va_end(args);
 }
+
+EXPORT_SYMBOL(snd_verbose_printk);
 #endif
 
 #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
@@ -71,4 +75,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
        va_end(args);
 
 }
+
+EXPORT_SYMBOL(snd_verbose_printd);
 #endif
index 9c68bc3f97aabc93c37f6420cccdc77ab01da34d..71b5080fa66d0dc603785046fcb001a341da9f74 100644 (file)
@@ -1182,9 +1182,7 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
                return;
        entry->content = SNDRV_INFO_CONTENT_TEXT;
        entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-       entry->c.text.read_size = 8192;
        entry->c.text.read = snd_mixer_oss_proc_read;
-       entry->c.text.write_size = 8192;
        entry->c.text.write = snd_mixer_oss_proc_write;
        entry->private_data = mixer;
        if (snd_info_register(entry) < 0) {
index ac990bf0b48f7ab11f5684d56b25fae795bd4d5e..f5ff4f4a16ee0b7964599c49f1311176dc7a6aa1 100644 (file)
@@ -45,7 +45,7 @@
 
 #define OSS_ALSAEMULVER                _SIOR ('M', 249, int)
 
-static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
+static int dsp_map[SNDRV_CARDS];
 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
 static int nonblock_open = 1;
 
@@ -78,6 +78,487 @@ static inline void snd_leave_user(mm_segment_t fs)
        set_fs(fs);
 }
 
+/*
+ * helper functions to process hw_params
+ */
+static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
+{
+       int changed = 0;
+       if (i->min < min) {
+               i->min = min;
+               i->openmin = openmin;
+               changed = 1;
+       } else if (i->min == min && !i->openmin && openmin) {
+               i->openmin = 1;
+               changed = 1;
+       }
+       if (i->integer) {
+               if (i->openmin) {
+                       i->min++;
+                       i->openmin = 0;
+               }
+       }
+       if (snd_interval_checkempty(i)) {
+               snd_interval_none(i);
+               return -EINVAL;
+       }
+       return changed;
+}
+
+static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
+{
+       int changed = 0;
+       if (i->max > max) {
+               i->max = max;
+               i->openmax = openmax;
+               changed = 1;
+       } else if (i->max == max && !i->openmax && openmax) {
+               i->openmax = 1;
+               changed = 1;
+       }
+       if (i->integer) {
+               if (i->openmax) {
+                       i->max--;
+                       i->openmax = 0;
+               }
+       }
+       if (snd_interval_checkempty(i)) {
+               snd_interval_none(i);
+               return -EINVAL;
+       }
+       return changed;
+}
+
+static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
+{
+       struct snd_interval t;
+       t.empty = 0;
+       t.min = t.max = val;
+       t.openmin = t.openmax = 0;
+       t.integer = 1;
+       return snd_interval_refine(i, &t);
+}
+
+/**
+ * snd_pcm_hw_param_value_min
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Return the minimum value for field PAR.
+ */
+static unsigned int
+snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
+                          snd_pcm_hw_param_t var, int *dir)
+{
+       if (hw_is_mask(var)) {
+               if (dir)
+                       *dir = 0;
+               return snd_mask_min(hw_param_mask_c(params, var));
+       }
+       if (hw_is_interval(var)) {
+               const struct snd_interval *i = hw_param_interval_c(params, var);
+               if (dir)
+                       *dir = i->openmin;
+               return snd_interval_min(i);
+       }
+       return -EINVAL;
+}
+
+/**
+ * snd_pcm_hw_param_value_max
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Return the maximum value for field PAR.
+ */
+static unsigned int
+snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
+                          snd_pcm_hw_param_t var, int *dir)
+{
+       if (hw_is_mask(var)) {
+               if (dir)
+                       *dir = 0;
+               return snd_mask_max(hw_param_mask_c(params, var));
+       }
+       if (hw_is_interval(var)) {
+               const struct snd_interval *i = hw_param_interval_c(params, var);
+               if (dir)
+                       *dir = - (int) i->openmax;
+               return snd_interval_max(i);
+       }
+       return -EINVAL;
+}
+
+static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
+                                 snd_pcm_hw_param_t var,
+                                 const struct snd_mask *val)
+{
+       int changed;
+       changed = snd_mask_refine(hw_param_mask(params, var), val);
+       if (changed) {
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
+       return changed;
+}
+
+static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm,
+                                struct snd_pcm_hw_params *params,
+                                snd_pcm_hw_param_t var,
+                                const struct snd_mask *val)
+{
+       int changed = _snd_pcm_hw_param_mask(params, var, val);
+       if (changed < 0)
+               return changed;
+       if (params->rmask) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
+                                snd_pcm_hw_param_t var, unsigned int val,
+                                int dir)
+{
+       int changed;
+       int open = 0;
+       if (dir) {
+               if (dir > 0) {
+                       open = 1;
+               } else if (dir < 0) {
+                       if (val > 0) {
+                               open = 1;
+                               val--;
+                       }
+               }
+       }
+       if (hw_is_mask(var))
+               changed = snd_mask_refine_min(hw_param_mask(params, var),
+                                             val + !!open);
+       else if (hw_is_interval(var))
+               changed = snd_interval_refine_min(hw_param_interval(params, var),
+                                                 val, open);
+       else
+               return -EINVAL;
+       if (changed) {
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
+       return changed;
+}
+
+/**
+ * snd_pcm_hw_param_min
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: minimal value
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all 
+ * values < VAL. Reduce configuration space accordingly.
+ * Return new minimum or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm,
+                               struct snd_pcm_hw_params *params,
+                               snd_pcm_hw_param_t var, unsigned int val,
+                               int *dir)
+{
+       int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
+       if (changed < 0)
+               return changed;
+       if (params->rmask) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_param_value_min(params, var, dir);
+}
+
+static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
+                                snd_pcm_hw_param_t var, unsigned int val,
+                                int dir)
+{
+       int changed;
+       int open = 0;
+       if (dir) {
+               if (dir < 0) {
+                       open = 1;
+               } else if (dir > 0) {
+                       open = 1;
+                       val++;
+               }
+       }
+       if (hw_is_mask(var)) {
+               if (val == 0 && open) {
+                       snd_mask_none(hw_param_mask(params, var));
+                       changed = -EINVAL;
+               } else
+                       changed = snd_mask_refine_max(hw_param_mask(params, var),
+                                                     val - !!open);
+       } else if (hw_is_interval(var))
+               changed = snd_interval_refine_max(hw_param_interval(params, var),
+                                                 val, open);
+       else
+               return -EINVAL;
+       if (changed) {
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
+       return changed;
+}
+
+/**
+ * snd_pcm_hw_param_max
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: maximal value
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all 
+ *  values >= VAL + 1. Reduce configuration space accordingly.
+ *  Return new maximum or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm,
+                               struct snd_pcm_hw_params *params,
+                               snd_pcm_hw_param_t var, unsigned int val,
+                               int *dir)
+{
+       int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
+       if (changed < 0)
+               return changed;
+       if (params->rmask) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_param_value_max(params, var, dir);
+}
+
+static int boundary_sub(int a, int adir,
+                       int b, int bdir,
+                       int *c, int *cdir)
+{
+       adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
+       bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
+       *c = a - b;
+       *cdir = adir - bdir;
+       if (*cdir == -2) {
+               (*c)--;
+       } else if (*cdir == 2) {
+               (*c)++;
+       }
+       return 0;
+}
+
+static int boundary_lt(unsigned int a, int adir,
+                      unsigned int b, int bdir)
+{
+       if (adir < 0) {
+               a--;
+               adir = 1;
+       } else if (adir > 0)
+               adir = 1;
+       if (bdir < 0) {
+               b--;
+               bdir = 1;
+       } else if (bdir > 0)
+               bdir = 1;
+       return a < b || (a == b && adir < bdir);
+}
+
+/* Return 1 if min is nearer to best than max */
+static int boundary_nearer(int min, int mindir,
+                          int best, int bestdir,
+                          int max, int maxdir)
+{
+       int dmin, dmindir;
+       int dmax, dmaxdir;
+       boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
+       boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
+       return boundary_lt(dmin, dmindir, dmax, dmaxdir);
+}
+
+/**
+ * snd_pcm_hw_param_near
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @best: value to set
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS set PAR to the available value
+ * nearest to VAL. Reduce configuration space accordingly.
+ * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
+ * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
+ * Return the value found.
+  */
+static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
+                                struct snd_pcm_hw_params *params,
+                                snd_pcm_hw_param_t var, unsigned int best,
+                                int *dir)
+{
+       struct snd_pcm_hw_params *save = NULL;
+       int v;
+       unsigned int saved_min;
+       int last = 0;
+       int min, max;
+       int mindir, maxdir;
+       int valdir = dir ? *dir : 0;
+       /* FIXME */
+       if (best > INT_MAX)
+               best = INT_MAX;
+       min = max = best;
+       mindir = maxdir = valdir;
+       if (maxdir > 0)
+               maxdir = 0;
+       else if (maxdir == 0)
+               maxdir = -1;
+       else {
+               maxdir = 1;
+               max--;
+       }
+       save = kmalloc(sizeof(*save), GFP_KERNEL);
+       if (save == NULL)
+               return -ENOMEM;
+       *save = *params;
+       saved_min = min;
+       min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
+       if (min >= 0) {
+               struct snd_pcm_hw_params *params1;
+               if (max < 0)
+                       goto _end;
+               if ((unsigned int)min == saved_min && mindir == valdir)
+                       goto _end;
+               params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
+               if (params1 == NULL) {
+                       kfree(save);
+                       return -ENOMEM;
+               }
+               *params1 = *save;
+               max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
+               if (max < 0) {
+                       kfree(params1);
+                       goto _end;
+               }
+               if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
+                       *params = *params1;
+                       last = 1;
+               }
+               kfree(params1);
+       } else {
+               *params = *save;
+               max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
+               snd_assert(max >= 0, return -EINVAL);
+               last = 1;
+       }
+ _end:
+       kfree(save);
+       if (last)
+               v = snd_pcm_hw_param_last(pcm, params, var, dir);
+       else
+               v = snd_pcm_hw_param_first(pcm, params, var, dir);
+       snd_assert(v >= 0, return -EINVAL);
+       return v;
+}
+
+static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
+                                snd_pcm_hw_param_t var, unsigned int val,
+                                int dir)
+{
+       int changed;
+       if (hw_is_mask(var)) {
+               struct snd_mask *m = hw_param_mask(params, var);
+               if (val == 0 && dir < 0) {
+                       changed = -EINVAL;
+                       snd_mask_none(m);
+               } else {
+                       if (dir > 0)
+                               val++;
+                       else if (dir < 0)
+                               val--;
+                       changed = snd_mask_refine_set(hw_param_mask(params, var), val);
+               }
+       } else if (hw_is_interval(var)) {
+               struct snd_interval *i = hw_param_interval(params, var);
+               if (val == 0 && dir < 0) {
+                       changed = -EINVAL;
+                       snd_interval_none(i);
+               } else if (dir == 0)
+                       changed = snd_interval_refine_set(i, val);
+               else {
+                       struct snd_interval t;
+                       t.openmin = 1;
+                       t.openmax = 1;
+                       t.empty = 0;
+                       t.integer = 0;
+                       if (dir < 0) {
+                               t.min = val - 1;
+                               t.max = val;
+                       } else {
+                               t.min = val;
+                               t.max = val+1;
+                       }
+                       changed = snd_interval_refine(i, &t);
+               }
+       } else
+               return -EINVAL;
+       if (changed) {
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
+       return changed;
+}
+
+/**
+ * snd_pcm_hw_param_set
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ * @var: parameter to retrieve
+ * @val: value to set
+ * @dir: pointer to the direction (-1,0,1) or NULL
+ *
+ * Inside configuration space defined by PARAMS remove from PAR all 
+ * values != VAL. Reduce configuration space accordingly.
+ *  Return VAL or -EINVAL if the configuration space is empty
+ */
+static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,
+                               struct snd_pcm_hw_params *params,
+                               snd_pcm_hw_param_t var, unsigned int val,
+                               int dir)
+{
+       int changed = _snd_pcm_hw_param_set(params, var, val, dir);
+       if (changed < 0)
+               return changed;
+       if (params->rmask) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_param_value(params, var, NULL);
+}
+
+static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
+                                       snd_pcm_hw_param_t var)
+{
+       int changed;
+       changed = snd_interval_setinteger(hw_param_interval(params, var));
+       if (changed) {
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
+       return changed;
+}
+       
+/*
+ * plugin
+ */
+
 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
 static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
 {
@@ -203,7 +684,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
        oss_buffer_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
        oss_buffer_size = 1 << ld2(oss_buffer_size);
-       if (atomic_read(&runtime->mmap_count)) {
+       if (atomic_read(&substream->mmap_count)) {
                if (oss_buffer_size > runtime->oss.mmap_bytes)
                        oss_buffer_size = runtime->oss.mmap_bytes;
        }
@@ -338,7 +819,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                goto failure;
        }
 
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                direct = 1;
        else
                direct = substream->oss.setup.direct;
@@ -347,7 +828,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
        _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
        snd_mask_none(&mask);
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
        else {
                snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
@@ -466,7 +947,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        } else {
                sw_params->start_threshold = runtime->boundary;
        }
-       if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+       if (atomic_read(&substream->mmap_count) ||
+           substream->stream == SNDRV_PCM_STREAM_CAPTURE)
                sw_params->stop_threshold = runtime->boundary;
        else
                sw_params->stop_threshold = runtime->buffer_size;
@@ -476,7 +958,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
                1 : runtime->period_size;
        sw_params->xfer_align = 1;
-       if (atomic_read(&runtime->mmap_count) ||
+       if (atomic_read(&substream->mmap_count) ||
            substream->oss.setup.nosilence) {
                sw_params->silence_threshold = 0;
                sw_params->silence_size = 0;
@@ -820,7 +1302,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
        ssize_t tmp;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                return -ENXIO;
 
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
@@ -850,7 +1332,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
                                if (runtime->oss.period_ptr == 0 ||
                                    runtime->oss.period_ptr == runtime->oss.buffer_used)
                                        runtime->oss.buffer_used = 0;
-                               else if ((substream->ffile->f_flags & O_NONBLOCK) != 0)
+                               else if ((substream->f_flags & O_NONBLOCK) != 0)
                                        return xfer > 0 ? xfer : -EAGAIN;
                        }
                } else {
@@ -863,7 +1345,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
                        buf += tmp;
                        bytes -= tmp;
                        xfer += tmp;
-                       if ((substream->ffile->f_flags & O_NONBLOCK) != 0 &&
+                       if ((substream->f_flags & O_NONBLOCK) != 0 &&
                            tmp != runtime->oss.period_bytes)
                                break;
                }
@@ -910,7 +1392,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
        ssize_t tmp;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                return -ENXIO;
 
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
@@ -1040,7 +1522,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
        if (substream != NULL) {
                runtime = substream->runtime;
-               if (atomic_read(&runtime->mmap_count))
+               if (atomic_read(&substream->mmap_count))
                        goto __direct;
                if ((err = snd_pcm_oss_make_ready(substream)) < 0)
                        return err;
@@ -1101,10 +1583,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                 * finish sync: drain the buffer
                 */
              __direct:
-               saved_f_flags = substream->ffile->f_flags;
-               substream->ffile->f_flags &= ~O_NONBLOCK;
+               saved_f_flags = substream->f_flags;
+               substream->f_flags &= ~O_NONBLOCK;
                err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
-               substream->ffile->f_flags = saved_f_flags;
+               substream->f_flags = saved_f_flags;
                if (err < 0)
                        return err;
                runtime->oss.prepare = 1;
@@ -1209,7 +1691,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
 
        if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
                return err;
-       if (atomic_read(&substream->runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                direct = 1;
        else
                direct = substream->oss.setup.direct;
@@ -1419,7 +1901,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
                if (trigger & PCM_ENABLE_OUTPUT) {
                        if (runtime->oss.trigger)
                                goto _skip1;
-                       if (atomic_read(&psubstream->runtime->mmap_count))
+                       if (atomic_read(&psubstream->mmap_count))
                                snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
                        runtime->oss.trigger = 1;
                        runtime->start_threshold = 1;
@@ -1537,7 +2019,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
        if (err < 0)
                return err;
        info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
-       if (atomic_read(&runtime->mmap_count)) {
+       if (atomic_read(&substream->mmap_count)) {
                snd_pcm_sframes_t n;
                n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
                if (n < 0)
@@ -1683,9 +2165,9 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
        substream->oss.oss = 1;
        substream->oss.setup = *setup;
        if (setup->nonblock)
-               substream->ffile->f_flags |= O_NONBLOCK;
+               substream->f_flags |= O_NONBLOCK;
        else if (setup->block)
-               substream->ffile->f_flags &= ~O_NONBLOCK;
+               substream->f_flags &= ~O_NONBLOCK;
        runtime = substream->runtime;
        runtime->oss.params = 1;
        runtime->oss.trigger = 1;
@@ -1742,6 +2224,7 @@ static int snd_pcm_oss_open_file(struct file *file,
            (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
                f_mode = FMODE_WRITE;
 
+       file->f_flags &= ~O_APPEND;
        for (idx = 0; idx < 2; idx++) {
                if (setup[idx].disable)
                        continue;
@@ -2059,6 +2542,7 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
        if (substream == NULL)
                return -ENXIO;
+       substream->f_flags = file->f_flags & O_NONBLOCK;
 #ifndef OSS_DEBUG
        return snd_pcm_oss_read1(substream, buf, count);
 #else
@@ -2080,6 +2564,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
        substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
        if (substream == NULL)
                return -ENXIO;
+       substream->f_flags = file->f_flags & O_NONBLOCK;
        result = snd_pcm_oss_write1(substream, buf, count);
 #ifdef OSS_DEBUG
        printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
@@ -2090,7 +2575,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
 static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
        else
                return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
@@ -2099,7 +2584,7 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
 static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
        else
                return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
@@ -2342,9 +2827,7 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
                if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
                        entry->content = SNDRV_INFO_CONTENT_TEXT;
                        entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-                       entry->c.text.read_size = 8192;
                        entry->c.text.read = snd_pcm_oss_proc_read;
-                       entry->c.text.write_size = 8192;
                        entry->c.text.write = snd_pcm_oss_proc_write;
                        entry->private_data = pstr;
                        if (snd_info_register(entry) < 0) {
index 84b00038236d49504e9a73b34234d964f2dc73fa..7581edd7b9ffbf354d8542b010aa16d671cfca63 100644 (file)
@@ -351,10 +351,8 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
                snd_iprintf(buffer, "closed\n");
                return;
        }
-       snd_pcm_stream_lock_irq(substream);
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                snd_iprintf(buffer, "no setup\n");
-               snd_pcm_stream_unlock_irq(substream);
                return;
        }
        snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
@@ -375,7 +373,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
                snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
        }
 #endif
-       snd_pcm_stream_unlock_irq(substream);
 }
 
 static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
@@ -387,10 +384,8 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
                snd_iprintf(buffer, "closed\n");
                return;
        }
-       snd_pcm_stream_lock_irq(substream);
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
                snd_iprintf(buffer, "no setup\n");
-               snd_pcm_stream_unlock_irq(substream);
                return;
        }
        snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
@@ -403,7 +398,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
        snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
        snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
-       snd_pcm_stream_unlock_irq(substream);
 }
 
 static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
@@ -472,7 +466,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
        pstr->proc_root = entry;
 
        if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) {
-               snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read);
+               snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
                        entry = NULL;
@@ -483,9 +477,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
        if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
                                                pstr->proc_root)) != NULL) {
-               entry->c.text.read_size = 64;
                entry->c.text.read = snd_pcm_xrun_debug_read;
-               entry->c.text.write_size = 64;
                entry->c.text.write = snd_pcm_xrun_debug_write;
                entry->mode |= S_IWUSR;
                entry->private_data = pstr;
@@ -537,7 +529,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
        substream->proc_root = entry;
 
        if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) {
-               snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read);
+               snd_info_set_text_ops(entry, substream,
+                                     snd_pcm_substream_proc_info_read);
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
                        entry = NULL;
@@ -546,7 +539,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
        substream->proc_info_entry = entry;
 
        if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) {
-               snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read);
+               snd_info_set_text_ops(entry, substream,
+                                     snd_pcm_substream_proc_hw_params_read);
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
                        entry = NULL;
@@ -555,7 +549,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
        substream->proc_hw_params_entry = entry;
 
        if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) {
-               snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read);
+               snd_info_set_text_ops(entry, substream,
+                                     snd_pcm_substream_proc_sw_params_read);
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
                        entry = NULL;
@@ -564,7 +559,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
        substream->proc_sw_params_entry = entry;
 
        if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) {
-               snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read);
+               snd_info_set_text_ops(entry, substream,
+                                     snd_pcm_substream_proc_status_read);
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
                        entry = NULL;
@@ -666,11 +662,14 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
                INIT_LIST_HEAD(&substream->self_group.substreams);
                list_add_tail(&substream->link_list, &substream->self_group.substreams);
                spin_lock_init(&substream->timer_lock);
+               atomic_set(&substream->mmap_count, 0);
                prev = substream;
        }
        return 0;
 }                              
 
+EXPORT_SYMBOL(snd_pcm_new_stream);
+
 /**
  * snd_pcm_new - create a new PCM instance
  * @card: the card instance
@@ -730,6 +729,8 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_new);
+
 static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
 {
        struct snd_pcm_substream *substream, *substream_next;
@@ -829,6 +830,26 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                return -EINVAL;
        }
 
+       if (file->f_flags & O_APPEND) {
+               if (prefer_subdevice < 0) {
+                       if (pstr->substream_count > 1)
+                               return -EINVAL; /* must be unique */
+                       substream = pstr->substream;
+               } else {
+                       for (substream = pstr->substream; substream;
+                            substream = substream->next)
+                               if (substream->number == prefer_subdevice)
+                                       break;
+               }
+               if (! substream)
+                       return -ENODEV;
+               if (! SUBSTREAM_BUSY(substream))
+                       return -EBADFD;
+               substream->ref_count++;
+               *rsubstream = substream;
+               return 0;
+       }
+
        if (prefer_subdevice >= 0) {
                for (substream = pstr->substream; substream; substream = substream->next)
                        if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
@@ -864,7 +885,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        memset((void*)runtime->control, 0, size);
 
        init_waitqueue_head(&runtime->sleep);
-       atomic_set(&runtime->mmap_count, 0);
        init_timer(&runtime->tick_timer);
        runtime->tick_timer.function = snd_pcm_tick_timer_func;
        runtime->tick_timer.data = (unsigned long) substream;
@@ -873,7 +893,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 
        substream->runtime = runtime;
        substream->private_data = pcm->private_data;
-       substream->ffile = file;
+       substream->ref_count = 1;
+       substream->f_flags = file->f_flags;
        pstr->substream_opened++;
        *rsubstream = substream;
        return 0;
@@ -882,7 +903,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
-       substream->file = NULL;
+
        runtime = substream->runtime;
        snd_assert(runtime != NULL, return);
        if (runtime->private_free != NULL)
@@ -1022,6 +1043,8 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_notify);
+
 #ifdef CONFIG_PROC_FS
 /*
  *  Info interface
@@ -1049,15 +1072,14 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry,
        mutex_unlock(&register_mutex);
 }
 
-static struct snd_info_entry *snd_pcm_proc_entry = NULL;
+static struct snd_info_entry *snd_pcm_proc_entry;
 
 static void snd_pcm_proc_init(void)
 {
        struct snd_info_entry *entry;
 
        if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
-               snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128,
-                                     snd_pcm_proc_read);
+               snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
                        entry = NULL;
@@ -1099,33 +1121,3 @@ static void __exit alsa_pcm_exit(void)
 
 module_init(alsa_pcm_init)
 module_exit(alsa_pcm_exit)
-
-EXPORT_SYMBOL(snd_pcm_new);
-EXPORT_SYMBOL(snd_pcm_new_stream);
-EXPORT_SYMBOL(snd_pcm_notify);
-EXPORT_SYMBOL(snd_pcm_open_substream);
-EXPORT_SYMBOL(snd_pcm_release_substream);
-  /* pcm_native.c */
-EXPORT_SYMBOL(snd_pcm_link_rwlock);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_pcm_suspend);
-EXPORT_SYMBOL(snd_pcm_suspend_all);
-#endif
-EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
-EXPORT_SYMBOL(snd_pcm_mmap_data);
-#if SNDRV_PCM_INFO_MMAP_IOMEM
-EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
-#endif
- /* pcm_misc.c */
-EXPORT_SYMBOL(snd_pcm_format_signed);
-EXPORT_SYMBOL(snd_pcm_format_unsigned);
-EXPORT_SYMBOL(snd_pcm_format_linear);
-EXPORT_SYMBOL(snd_pcm_format_little_endian);
-EXPORT_SYMBOL(snd_pcm_format_big_endian);
-EXPORT_SYMBOL(snd_pcm_format_width);
-EXPORT_SYMBOL(snd_pcm_format_physical_width);
-EXPORT_SYMBOL(snd_pcm_format_size);
-EXPORT_SYMBOL(snd_pcm_format_silence_64);
-EXPORT_SYMBOL(snd_pcm_format_set_silence);
-EXPORT_SYMBOL(snd_pcm_build_linear_format);
-EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
index e5133033de5e5fdf049ab51d2001677c58555738..2b8aab6fd6cd312365a658c2aefd074a7768df64 100644 (file)
@@ -497,9 +497,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
        case SNDRV_PCM_IOCTL_LINK:
        case SNDRV_PCM_IOCTL_UNLINK:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       return snd_pcm_playback_ioctl1(substream, cmd, argp);
+                       return snd_pcm_playback_ioctl1(file, substream, cmd, argp);
                else
-                       return snd_pcm_capture_ioctl1(substream, cmd, argp);
+                       return snd_pcm_capture_ioctl1(file, substream, cmd, argp);
        case SNDRV_PCM_IOCTL_HW_REFINE32:
                return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
        case SNDRV_PCM_IOCTL_HW_PARAMS32:
index eedc6cb038bb172e36c3643dbf7d77031fafc0b0..0bb142a28539fe93c6be231b715b076821a33b3f 100644 (file)
@@ -289,6 +289,7 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops
                substream->ops = ops;
 }
 
+EXPORT_SYMBOL(snd_pcm_set_ops);
 
 /**
  * snd_pcm_sync - set the PCM sync id
@@ -306,13 +307,12 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream)
        runtime->sync.id32[3] = -1;
 }
 
+EXPORT_SYMBOL(snd_pcm_set_sync);
+
 /*
  *  Standard ioctl routine
  */
 
-/* Code taken from alsa-lib */
-#define assert(a) snd_assert((a), return -EINVAL)
-
 static inline unsigned int div32(unsigned int a, unsigned int b, 
                                 unsigned int *r)
 {
@@ -369,56 +369,6 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
        return n;
 }
 
-static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin)
-{
-       int changed = 0;
-       assert(!snd_interval_empty(i));
-       if (i->min < min) {
-               i->min = min;
-               i->openmin = openmin;
-               changed = 1;
-       } else if (i->min == min && !i->openmin && openmin) {
-               i->openmin = 1;
-               changed = 1;
-       }
-       if (i->integer) {
-               if (i->openmin) {
-                       i->min++;
-                       i->openmin = 0;
-               }
-       }
-       if (snd_interval_checkempty(i)) {
-               snd_interval_none(i);
-               return -EINVAL;
-       }
-       return changed;
-}
-
-static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax)
-{
-       int changed = 0;
-       assert(!snd_interval_empty(i));
-       if (i->max > max) {
-               i->max = max;
-               i->openmax = openmax;
-               changed = 1;
-       } else if (i->max == max && !i->openmax && openmax) {
-               i->openmax = 1;
-               changed = 1;
-       }
-       if (i->integer) {
-               if (i->openmax) {
-                       i->max--;
-                       i->openmax = 0;
-               }
-       }
-       if (snd_interval_checkempty(i)) {
-               snd_interval_none(i);
-               return -EINVAL;
-       }
-       return changed;
-}
-
 /**
  * snd_interval_refine - refine the interval value of configurator
  * @i: the interval value to refine
@@ -433,7 +383,7 @@ static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
 {
        int changed = 0;
-       assert(!snd_interval_empty(i));
+       snd_assert(!snd_interval_empty(i), return -EINVAL);
        if (i->min < v->min) {
                i->min = v->min;
                i->openmin = v->openmin;
@@ -472,9 +422,11 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
        return changed;
 }
 
+EXPORT_SYMBOL(snd_interval_refine);
+
 static int snd_interval_refine_first(struct snd_interval *i)
 {
-       assert(!snd_interval_empty(i));
+       snd_assert(!snd_interval_empty(i), return -EINVAL);
        if (snd_interval_single(i))
                return 0;
        i->max = i->min;
@@ -486,7 +438,7 @@ static int snd_interval_refine_first(struct snd_interval *i)
 
 static int snd_interval_refine_last(struct snd_interval *i)
 {
-       assert(!snd_interval_empty(i));
+       snd_assert(!snd_interval_empty(i), return -EINVAL);
        if (snd_interval_single(i))
                return 0;
        i->min = i->max;
@@ -496,16 +448,6 @@ static int snd_interval_refine_last(struct snd_interval *i)
        return 1;
 }
 
-static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
-{
-       struct snd_interval t;
-       t.empty = 0;
-       t.min = t.max = val;
-       t.openmin = t.openmax = 0;
-       t.integer = 1;
-       return snd_interval_refine(i, &t);
-}
-
 void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
 {
        if (a->empty || b->empty) {
@@ -621,7 +563,6 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
        c->integer = 0;
 }
 
-#undef assert
 /* ---- */
 
 
@@ -727,6 +668,8 @@ int snd_interval_ratnum(struct snd_interval *i,
        return err;
 }
 
+EXPORT_SYMBOL(snd_interval_ratnum);
+
 /**
  * snd_interval_ratden - refine the interval value
  * @i: interval to refine
@@ -877,6 +820,8 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *
         return changed;
 }
 
+EXPORT_SYMBOL(snd_interval_list);
+
 static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step)
 {
        unsigned int n;
@@ -953,6 +898,8 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
        return 0;
 }                                  
 
+EXPORT_SYMBOL(snd_pcm_hw_rule_add);
+
 /**
  * snd_pcm_hw_constraint_mask
  * @runtime: PCM runtime instance
@@ -1007,6 +954,8 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa
        return snd_interval_setinteger(constrs_interval(constrs, var));
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
+
 /**
  * snd_pcm_hw_constraint_minmax
  * @runtime: PCM runtime instance
@@ -1028,6 +977,8 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
        return snd_interval_refine(constrs_interval(constrs, var), &t);
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
+
 static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
                                struct snd_pcm_hw_rule *rule)
 {
@@ -1055,6 +1006,8 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
                                   var, -1);
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
+
 static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
@@ -1087,6 +1040,8 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
                                   var, -1);
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
+
 static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
@@ -1118,6 +1073,8 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
                                   var, -1);
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
+
 static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
                                  struct snd_pcm_hw_rule *rule)
 {
@@ -1149,6 +1106,8 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
                                    SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
+
 static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
                                struct snd_pcm_hw_rule *rule)
 {
@@ -1173,6 +1132,8 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
                                   var, -1);
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
+
 static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
 {
        static int pow2_sizes[] = {
@@ -1200,11 +1161,7 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
                                   var, -1);
 }
 
-/* To use the same code we have in alsa-lib */
-#define assert(i) snd_assert((i), return -EINVAL)
-#ifndef INT_MIN
-#define INT_MIN ((int)((unsigned int)INT_MAX+1))
-#endif
+EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
 
 static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
                                  snd_pcm_hw_param_t var)
@@ -1224,18 +1181,6 @@ static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
        snd_BUG();
 }
 
-#if 0
-/*
- * snd_pcm_hw_param_any
- */
-int snd_pcm_hw_param_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
-                        snd_pcm_hw_param_t var)
-{
-       _snd_pcm_hw_param_any(params, var);
-       return snd_pcm_hw_refine(pcm, params);
-}
-#endif  /*  0  */
-
 void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
 {
        unsigned int k;
@@ -1247,18 +1192,7 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
        params->info = ~0U;
 }
 
-#if 0
-/*
- * snd_pcm_hw_params_any
- *
- * Fill PARAMS with full configuration space boundaries
- */
-int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params)
-{
-       _snd_pcm_hw_params_any(params);
-       return snd_pcm_hw_refine(pcm, params);
-}
-#endif  /*  0  */
+EXPORT_SYMBOL(_snd_pcm_hw_params_any);
 
 /**
  * snd_pcm_hw_param_value
@@ -1269,8 +1203,8 @@ int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_param
  * Return the value for field PAR if it's fixed in configuration space 
  *  defined by PARAMS. Return -EINVAL otherwise
  */
-static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
-                                 snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
+                          snd_pcm_hw_param_t var, int *dir)
 {
        if (hw_is_mask(var)) {
                const struct snd_mask *mask = hw_param_mask_c(params, var);
@@ -1288,61 +1222,10 @@ static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
                        *dir = i->openmin;
                return snd_interval_value(i);
        }
-       assert(0);
-       return -EINVAL;
-}
-
-/**
- * snd_pcm_hw_param_value_min
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the minimum value for field PAR.
- */
-unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
-                                       snd_pcm_hw_param_t var, int *dir)
-{
-       if (hw_is_mask(var)) {
-               if (dir)
-                       *dir = 0;
-               return snd_mask_min(hw_param_mask_c(params, var));
-       }
-       if (hw_is_interval(var)) {
-               const struct snd_interval *i = hw_param_interval_c(params, var);
-               if (dir)
-                       *dir = i->openmin;
-               return snd_interval_min(i);
-       }
-       assert(0);
        return -EINVAL;
 }
 
-/**
- * snd_pcm_hw_param_value_max
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Return the maximum value for field PAR.
- */
-unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
-                                       snd_pcm_hw_param_t var, int *dir)
-{
-       if (hw_is_mask(var)) {
-               if (dir)
-                       *dir = 0;
-               return snd_mask_max(hw_param_mask_c(params, var));
-       }
-       if (hw_is_interval(var)) {
-               const struct snd_interval *i = hw_param_interval_c(params, var);
-               if (dir)
-                       *dir = - (int) i->openmax;
-               return snd_interval_max(i);
-       }
-       assert(0);
-       return -EINVAL;
-}
+EXPORT_SYMBOL(snd_pcm_hw_param_value);
 
 void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
                                snd_pcm_hw_param_t var)
@@ -1360,42 +1243,7 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
        }
 }
 
-int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var)
-{
-       int changed;
-       assert(hw_is_interval(var));
-       changed = snd_interval_setinteger(hw_param_interval(params, var));
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-       
-#if 0
-/*
- * snd_pcm_hw_param_setinteger
- *
- * Inside configuration space defined by PARAMS remove from PAR all 
- * non integer values. Reduce configuration space accordingly.
- * Return -EINVAL if the configuration space is empty
- */
-int snd_pcm_hw_param_setinteger(struct snd_pcm_substream *pcm, 
-                               struct snd_pcm_hw_params *params,
-                               snd_pcm_hw_param_t var)
-{
-       int changed = _snd_pcm_hw_param_setinteger(params, var);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-#endif  /*  0  */
+EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
 
 static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
                                   snd_pcm_hw_param_t var)
@@ -1405,10 +1253,8 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
                changed = snd_mask_refine_first(hw_param_mask(params, var));
        else if (hw_is_interval(var))
                changed = snd_interval_refine_first(hw_param_interval(params, var));
-       else {
-               assert(0);
+       else
                return -EINVAL;
-       }
        if (changed) {
                params->cmask |= 1 << var;
                params->rmask |= 1 << var;
@@ -1428,20 +1274,22 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
  * values > minimum. Reduce configuration space accordingly.
  * Return the minimum.
  */
-static int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 
-                                 struct snd_pcm_hw_params *params, 
-                                 snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 
+                          struct snd_pcm_hw_params *params, 
+                          snd_pcm_hw_param_t var, int *dir)
 {
        int changed = _snd_pcm_hw_param_first(params, var);
        if (changed < 0)
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               assert(err >= 0);
+               snd_assert(err >= 0, return err);
        }
        return snd_pcm_hw_param_value(params, var, dir);
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_param_first);
+
 static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
                                  snd_pcm_hw_param_t var)
 {
@@ -1450,10 +1298,8 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
                changed = snd_mask_refine_last(hw_param_mask(params, var));
        else if (hw_is_interval(var))
                changed = snd_interval_refine_last(hw_param_interval(params, var));
-       else {
-               assert(0);
+       else
                return -EINVAL;
-       }
        if (changed) {
                params->cmask |= 1 << var;
                params->rmask |= 1 << var;
@@ -1473,381 +1319,21 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
  * values < maximum. Reduce configuration space accordingly.
  * Return the maximum.
  */
-static int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, 
-                                struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, int *dir)
+int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, 
+                         struct snd_pcm_hw_params *params,
+                         snd_pcm_hw_param_t var, int *dir)
 {
        int changed = _snd_pcm_hw_param_last(params, var);
        if (changed < 0)
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               assert(err >= 0);
+               snd_assert(err >= 0, return err);
        }
        return snd_pcm_hw_param_value(params, var, dir);
 }
 
-int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params,
-                         snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
-       int changed;
-       int open = 0;
-       if (dir) {
-               if (dir > 0) {
-                       open = 1;
-               } else if (dir < 0) {
-                       if (val > 0) {
-                               open = 1;
-                               val--;
-                       }
-               }
-       }
-       if (hw_is_mask(var))
-               changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!open);
-       else if (hw_is_interval(var))
-               changed = snd_interval_refine_min(hw_param_interval(params, var), val, open);
-       else {
-               assert(0);
-               return -EINVAL;
-       }
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-/**
- * snd_pcm_hw_param_min
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: minimal value
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all 
- * values < VAL. Reduce configuration space accordingly.
- * Return new minimum or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
-                               snd_pcm_hw_param_t var, unsigned int val,
-                               int *dir)
-{
-       int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return snd_pcm_hw_param_value_min(params, var, dir);
-}
-
-static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params,
-                                snd_pcm_hw_param_t var, unsigned int val,
-                                int dir)
-{
-       int changed;
-       int open = 0;
-       if (dir) {
-               if (dir < 0) {
-                       open = 1;
-               } else if (dir > 0) {
-                       open = 1;
-                       val++;
-               }
-       }
-       if (hw_is_mask(var)) {
-               if (val == 0 && open) {
-                       snd_mask_none(hw_param_mask(params, var));
-                       changed = -EINVAL;
-               } else
-                       changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!open);
-       } else if (hw_is_interval(var))
-               changed = snd_interval_refine_max(hw_param_interval(params, var), val, open);
-       else {
-               assert(0);
-               return -EINVAL;
-       }
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-/**
- * snd_pcm_hw_param_max
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: maximal value
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all 
- *  values >= VAL + 1. Reduce configuration space accordingly.
- *  Return new maximum or -EINVAL if the configuration space is empty
- */
-static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
-                               snd_pcm_hw_param_t var, unsigned int val,
-                               int *dir)
-{
-       int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return snd_pcm_hw_param_value_max(params, var, dir);
-}
-
-int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
-                         snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
-       int changed;
-       if (hw_is_mask(var)) {
-               struct snd_mask *m = hw_param_mask(params, var);
-               if (val == 0 && dir < 0) {
-                       changed = -EINVAL;
-                       snd_mask_none(m);
-               } else {
-                       if (dir > 0)
-                               val++;
-                       else if (dir < 0)
-                               val--;
-                       changed = snd_mask_refine_set(hw_param_mask(params, var), val);
-               }
-       } else if (hw_is_interval(var)) {
-               struct snd_interval *i = hw_param_interval(params, var);
-               if (val == 0 && dir < 0) {
-                       changed = -EINVAL;
-                       snd_interval_none(i);
-               } else if (dir == 0)
-                       changed = snd_interval_refine_set(i, val);
-               else {
-                       struct snd_interval t;
-                       t.openmin = 1;
-                       t.openmax = 1;
-                       t.empty = 0;
-                       t.integer = 0;
-                       if (dir < 0) {
-                               t.min = val - 1;
-                               t.max = val;
-                       } else {
-                               t.min = val;
-                               t.max = val+1;
-                       }
-                       changed = snd_interval_refine(i, &t);
-               }
-       } else {
-               assert(0);
-               return -EINVAL;
-       }
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-/**
- * snd_pcm_hw_param_set
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS remove from PAR all 
- * values != VAL. Reduce configuration space accordingly.
- *  Return VAL or -EINVAL if the configuration space is empty
- */
-int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
-                        snd_pcm_hw_param_t var, unsigned int val, int dir)
-{
-       int changed = _snd_pcm_hw_param_set(params, var, val, dir);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return snd_pcm_hw_param_value(params, var, NULL);
-}
-
-static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params,
-                                 snd_pcm_hw_param_t var, const struct snd_mask *val)
-{
-       int changed;
-       assert(hw_is_mask(var));
-       changed = snd_mask_refine(hw_param_mask(params, var), val);
-       if (changed) {
-               params->cmask |= 1 << var;
-               params->rmask |= 1 << var;
-       }
-       return changed;
-}
-
-/**
- * snd_pcm_hw_param_mask
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @val: mask to apply
- *
- * Inside configuration space defined by PARAMS remove from PAR all values
- * not contained in MASK. Reduce configuration space accordingly.
- * This function can be called only for SNDRV_PCM_HW_PARAM_ACCESS,
- * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
- * Return 0 on success or -EINVAL
- * if the configuration space is empty
- */
-int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
-                         snd_pcm_hw_param_t var, const struct snd_mask *val)
-{
-       int changed = _snd_pcm_hw_param_mask(params, var, val);
-       if (changed < 0)
-               return changed;
-       if (params->rmask) {
-               int err = snd_pcm_hw_refine(pcm, params);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static int boundary_sub(int a, int adir,
-                       int b, int bdir,
-                       int *c, int *cdir)
-{
-       adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
-       bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
-       *c = a - b;
-       *cdir = adir - bdir;
-       if (*cdir == -2) {
-               assert(*c > INT_MIN);
-               (*c)--;
-       } else if (*cdir == 2) {
-               assert(*c < INT_MAX);
-               (*c)++;
-       }
-       return 0;
-}
-
-static int boundary_lt(unsigned int a, int adir,
-                      unsigned int b, int bdir)
-{
-       assert(a > 0 || adir >= 0);
-       assert(b > 0 || bdir >= 0);
-       if (adir < 0) {
-               a--;
-               adir = 1;
-       } else if (adir > 0)
-               adir = 1;
-       if (bdir < 0) {
-               b--;
-               bdir = 1;
-       } else if (bdir > 0)
-               bdir = 1;
-       return a < b || (a == b && adir < bdir);
-}
-
-/* Return 1 if min is nearer to best than max */
-static int boundary_nearer(int min, int mindir,
-                          int best, int bestdir,
-                          int max, int maxdir)
-{
-       int dmin, dmindir;
-       int dmax, dmaxdir;
-       boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
-       boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
-       return boundary_lt(dmin, dmindir, dmax, dmaxdir);
-}
-
-/**
- * snd_pcm_hw_param_near
- * @pcm: PCM instance
- * @params: the hw_params instance
- * @var: parameter to retrieve
- * @best: value to set
- * @dir: pointer to the direction (-1,0,1) or NULL
- *
- * Inside configuration space defined by PARAMS set PAR to the available value
- * nearest to VAL. Reduce configuration space accordingly.
- * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
- * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
- * Return the value found.
-  */
-int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params,
-                         snd_pcm_hw_param_t var, unsigned int best, int *dir)
-{
-       struct snd_pcm_hw_params *save = NULL;
-       int v;
-       unsigned int saved_min;
-       int last = 0;
-       int min, max;
-       int mindir, maxdir;
-       int valdir = dir ? *dir : 0;
-       /* FIXME */
-       if (best > INT_MAX)
-               best = INT_MAX;
-       min = max = best;
-       mindir = maxdir = valdir;
-       if (maxdir > 0)
-               maxdir = 0;
-       else if (maxdir == 0)
-               maxdir = -1;
-       else {
-               maxdir = 1;
-               max--;
-       }
-       save = kmalloc(sizeof(*save), GFP_KERNEL);
-       if (save == NULL)
-               return -ENOMEM;
-       *save = *params;
-       saved_min = min;
-       min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
-       if (min >= 0) {
-               struct snd_pcm_hw_params *params1;
-               if (max < 0)
-                       goto _end;
-               if ((unsigned int)min == saved_min && mindir == valdir)
-                       goto _end;
-               params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
-               if (params1 == NULL) {
-                       kfree(save);
-                       return -ENOMEM;
-               }
-               *params1 = *save;
-               max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
-               if (max < 0) {
-                       kfree(params1);
-                       goto _end;
-               }
-               if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
-                       *params = *params1;
-                       last = 1;
-               }
-               kfree(params1);
-       } else {
-               *params = *save;
-               max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
-               assert(max >= 0);
-               last = 1;
-       }
- _end:
-       kfree(save);
-       if (last)
-               v = snd_pcm_hw_param_last(pcm, params, var, dir);
-       else
-               v = snd_pcm_hw_param_first(pcm, params, var, dir);
-       assert(v >= 0);
-       return v;
-}
+EXPORT_SYMBOL(snd_pcm_hw_param_last);
 
 /**
  * snd_pcm_hw_param_choose
@@ -1859,39 +1345,32 @@ int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_param
  * first access, first format, first subformat, min channels,
  * min rate, min period time, max buffer size, min tick time
  */
-int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params)
-{
-       int err;
-
-       err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_ACCESS, NULL);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_FORMAT, NULL);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_SUBFORMAT, NULL);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_CHANNELS, NULL);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_RATE, NULL);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, NULL);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_param_last(pcm, params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_TICK_TIME, NULL);
-       assert(err >= 0);
+int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
+                            struct snd_pcm_hw_params *params)
+{
+       static int vars[] = {
+               SNDRV_PCM_HW_PARAM_ACCESS,
+               SNDRV_PCM_HW_PARAM_FORMAT,
+               SNDRV_PCM_HW_PARAM_SUBFORMAT,
+               SNDRV_PCM_HW_PARAM_CHANNELS,
+               SNDRV_PCM_HW_PARAM_RATE,
+               SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+               SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+               SNDRV_PCM_HW_PARAM_TICK_TIME,
+               -1
+       };
+       int err, *v;
 
+       for (v = vars; *v != -1; v++) {
+               if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
+                       err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
+               else
+                       err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
+               snd_assert(err >= 0, return err);
+       }
        return 0;
 }
 
-#undef assert
-
 static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
                                   void *arg)
 {
@@ -1967,6 +1446,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
        return -ENXIO;
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_ioctl);
+
 /*
  *  Conditions
  */
@@ -2101,6 +1582,8 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
        kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
 }
 
+EXPORT_SYMBOL(snd_pcm_period_elapsed);
+
 static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
                                      unsigned int hwoff,
                                      unsigned long data, unsigned int off,
@@ -2299,7 +1782,7 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
 
-       nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+       nonblock = !!(substream->f_flags & O_NONBLOCK);
 
        if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
            runtime->channels > 1)
@@ -2308,6 +1791,8 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v
                                  snd_pcm_lib_write_transfer);
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_write);
+
 static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
                                       unsigned int hwoff,
                                       unsigned long data, unsigned int off,
@@ -2362,7 +1847,7 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
 
-       nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+       nonblock = !!(substream->f_flags & O_NONBLOCK);
 
        if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
                return -EINVAL;
@@ -2370,6 +1855,8 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
                                  nonblock, snd_pcm_lib_writev_transfer);
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_writev);
+
 static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, 
                                     unsigned int hwoff,
                                     unsigned long data, unsigned int off,
@@ -2572,12 +2059,14 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
 
-       nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+       nonblock = !!(substream->f_flags & O_NONBLOCK);
        if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
                return -EINVAL;
        return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_read);
+
 static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
                                      unsigned int hwoff,
                                      unsigned long data, unsigned int off,
@@ -2629,58 +2118,10 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
 
-       nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
+       nonblock = !!(substream->f_flags & O_NONBLOCK);
        if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
                return -EINVAL;
        return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
 }
 
-/*
- *  Exported symbols
- */
-
-EXPORT_SYMBOL(snd_interval_refine);
-EXPORT_SYMBOL(snd_interval_list);
-EXPORT_SYMBOL(snd_interval_ratnum);
-EXPORT_SYMBOL(_snd_pcm_hw_params_any);
-EXPORT_SYMBOL(_snd_pcm_hw_param_min);
-EXPORT_SYMBOL(_snd_pcm_hw_param_set);
-EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
-EXPORT_SYMBOL(_snd_pcm_hw_param_setinteger);
-EXPORT_SYMBOL(snd_pcm_hw_param_value_min);
-EXPORT_SYMBOL(snd_pcm_hw_param_value_max);
-EXPORT_SYMBOL(snd_pcm_hw_param_mask);
-EXPORT_SYMBOL(snd_pcm_hw_param_first);
-EXPORT_SYMBOL(snd_pcm_hw_param_last);
-EXPORT_SYMBOL(snd_pcm_hw_param_near);
-EXPORT_SYMBOL(snd_pcm_hw_param_set);
-EXPORT_SYMBOL(snd_pcm_hw_refine);
-EXPORT_SYMBOL(snd_pcm_hw_constraints_init);
-EXPORT_SYMBOL(snd_pcm_hw_constraints_complete);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
-EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
-EXPORT_SYMBOL(snd_pcm_hw_rule_add);
-EXPORT_SYMBOL(snd_pcm_set_ops);
-EXPORT_SYMBOL(snd_pcm_set_sync);
-EXPORT_SYMBOL(snd_pcm_lib_ioctl);
-EXPORT_SYMBOL(snd_pcm_stop);
-EXPORT_SYMBOL(snd_pcm_period_elapsed);
-EXPORT_SYMBOL(snd_pcm_lib_write);
-EXPORT_SYMBOL(snd_pcm_lib_read);
-EXPORT_SYMBOL(snd_pcm_lib_writev);
 EXPORT_SYMBOL(snd_pcm_lib_readv);
-EXPORT_SYMBOL(snd_pcm_lib_buffer_bytes);
-EXPORT_SYMBOL(snd_pcm_lib_period_bytes);
-/* pcm_memory.c */
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
-EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
-EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
-EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
-EXPORT_SYMBOL(snd_pcm_lib_free_pages);
index 428f8c169ee15406a7ad6c3d2bd8b90cba5b75f6..067d2056db9a65569580945f3e9d1529de32dce0 100644 (file)
@@ -126,6 +126,8 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
+
 #ifdef CONFIG_SND_VERBOSE_PROCFS
 /*
  * read callback for prealloc proc file
@@ -191,9 +193,7 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream)
        struct snd_info_entry *entry;
 
        if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) {
-               entry->c.text.read_size = 64;
                entry->c.text.read = snd_pcm_lib_preallocate_proc_read;
-               entry->c.text.write_size = 64;
                entry->c.text.write = snd_pcm_lib_preallocate_proc_write;
                entry->mode |= S_IWUSR;
                entry->private_data = substream;
@@ -253,6 +253,8 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
        return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
+
 /**
  * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams)
  * @pcm: the pcm instance
@@ -280,6 +282,8 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
+
 /**
  * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
  * @substream: the pcm substream instance
@@ -298,6 +302,8 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
        return sgbuf->page_table[idx];
 }
 
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
+
 /**
  * snd_pcm_lib_malloc_pages - allocate the DMA buffer
  * @substream: the substream to allocate the DMA buffer to
@@ -349,6 +355,8 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
        return 1;                       /* area was changed */
 }
 
+EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
+
 /**
  * snd_pcm_lib_free_pages - release the allocated DMA buffer.
  * @substream: the substream to release the DMA buffer
@@ -374,3 +382,5 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
        snd_pcm_set_runtime_buffer(substream, NULL);
        return 0;
 }
+
+EXPORT_SYMBOL(snd_pcm_lib_free_pages);
index 593c77f4d181bcfe0fb55d0e5e0349ec3fdc90ba..0019c59a779d25a0cc772826d03a0de2f3d75957 100644 (file)
@@ -207,6 +207,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
        return val;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_signed);
+
 /**
  * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
  * @format: the format to check
@@ -224,6 +226,8 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format)
        return !val;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_unsigned);
+
 /**
  * snd_pcm_format_linear - Check the PCM format is linear
  * @format: the format to check
@@ -235,6 +239,8 @@ int snd_pcm_format_linear(snd_pcm_format_t format)
        return snd_pcm_format_signed(format) >= 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_linear);
+
 /**
  * snd_pcm_format_little_endian - Check the PCM format is little-endian
  * @format: the format to check
@@ -252,6 +258,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
        return val;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_little_endian);
+
 /**
  * snd_pcm_format_big_endian - Check the PCM format is big-endian
  * @format: the format to check
@@ -269,6 +277,8 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format)
        return !val;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_big_endian);
+
 /**
  * snd_pcm_format_width - return the bit-width of the format
  * @format: the format to check
@@ -286,6 +296,8 @@ int snd_pcm_format_width(snd_pcm_format_t format)
        return val;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_width);
+
 /**
  * snd_pcm_format_physical_width - return the physical bit-width of the format
  * @format: the format to check
@@ -303,6 +315,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
        return val;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_physical_width);
+
 /**
  * snd_pcm_format_size - return the byte size of samples on the given format
  * @format: the format to check
@@ -318,6 +332,8 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
        return samples * phys_width / 8;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_size);
+
 /**
  * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
  * @format: the format to check
@@ -333,6 +349,8 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
        return pcm_formats[format].silence;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_silence_64);
+
 /**
  * snd_pcm_format_set_silence - set the silence data on the buffer
  * @format: the PCM format
@@ -402,6 +420,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
        return 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_format_set_silence);
+
 /* [width][unsigned][bigendian] */
 static int linear_formats[4][2][2] = {
        {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8},
@@ -432,6 +452,8 @@ snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_end
        return linear_formats[width][!!unsignd][!!big_endian];
 }
 
+EXPORT_SYMBOL(snd_pcm_build_linear_format);
+
 /**
  * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
  * @runtime: the runtime instance
@@ -463,3 +485,5 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
        }
        return 0;
 }
+
+EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
index 0860c5a84502f6f67451cdea60a566b639fdbf9b..439f047929e18e509961214878ffd36233d71371 100644 (file)
@@ -71,8 +71,9 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
  */
 
 DEFINE_RWLOCK(snd_pcm_link_rwlock);
-static DECLARE_RWSEM(snd_pcm_link_rwsem);
+EXPORT_SYMBOL(snd_pcm_link_rwlock);
 
+static DECLARE_RWSEM(snd_pcm_link_rwsem);
 
 static inline mm_segment_t snd_enter_user(void)
 {
@@ -319,6 +320,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_hw_refine);
+
 static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params __user * _params)
 {
@@ -369,7 +372,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        if (!substream->oss.oss)
 #endif
-               if (atomic_read(&runtime->mmap_count))
+               if (atomic_read(&substream->mmap_count))
                        return -EBADFD;
 
        params->rmask = ~0U;
@@ -482,7 +485,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
                return -EBADFD;
        }
        snd_pcm_stream_unlock_irq(substream);
-       if (atomic_read(&runtime->mmap_count))
+       if (atomic_read(&substream->mmap_count))
                return -EBADFD;
        if (substream->ops->hw_free)
                result = substream->ops->hw_free(substream);
@@ -936,6 +939,8 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, int state)
        return snd_pcm_action(&snd_pcm_action_stop, substream, state);
 }
 
+EXPORT_SYMBOL(snd_pcm_stop);
+
 /**
  * snd_pcm_drain_done
  * @substream: the PCM substream
@@ -1085,6 +1090,8 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream)
        return err;
 }
 
+EXPORT_SYMBOL(snd_pcm_suspend);
+
 /**
  * snd_pcm_suspend_all
  * @pcm: the PCM instance
@@ -1114,6 +1121,8 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_pcm_suspend_all);
+
 /* resume */
 
 static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state)
@@ -1275,13 +1284,16 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream)
 /*
  * prepare ioctl
  */
-static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, int state)
+/* we use the second argument for updating f_flags */
+static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
+                              int f_flags)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
        if (snd_pcm_running(substream))
                return -EBUSY;
+       substream->f_flags = f_flags;
        return 0;
 }
 
@@ -1310,17 +1322,26 @@ static struct action_ops snd_pcm_action_prepare = {
 /**
  * snd_pcm_prepare
  * @substream: the PCM substream instance
+ * @file: file to refer f_flags
  *
  * Prepare the PCM substream to be triggerable.
  */
-static int snd_pcm_prepare(struct snd_pcm_substream *substream)
+static int snd_pcm_prepare(struct snd_pcm_substream *substream,
+                          struct file *file)
 {
        int res;
        struct snd_card *card = substream->pcm->card;
+       int f_flags;
+
+       if (file)
+               f_flags = file->f_flags;
+       else
+               f_flags = substream->f_flags;
 
        snd_power_lock(card);
        if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
-               res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0);
+               res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
+                                              substream, f_flags);
        snd_power_unlock(card);
        return res;
 }
@@ -1331,7 +1352,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream)
 
 static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
 {
-       if (substream->ffile->f_flags & O_NONBLOCK)
+       if (substream->f_flags & O_NONBLOCK)
                return -EAGAIN;
        substream->runtime->trigger_master = substream;
        return 0;
@@ -1448,8 +1469,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
                }
        }
        up_read(&snd_pcm_link_rwsem);
-       if (! num_drecs)
-               goto _error;
 
        snd_pcm_stream_lock_irq(substream);
        /* resume pause */
@@ -2006,6 +2025,10 @@ static void pcm_release_private(struct snd_pcm_substream *substream)
 
 void snd_pcm_release_substream(struct snd_pcm_substream *substream)
 {
+       substream->ref_count--;
+       if (substream->ref_count > 0)
+               return;
+
        snd_pcm_drop(substream);
        if (substream->hw_opened) {
                if (substream->ops->hw_free != NULL)
@@ -2020,6 +2043,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
        snd_pcm_detach_substream(substream);
 }
 
+EXPORT_SYMBOL(snd_pcm_release_substream);
+
 int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
                           struct file *file,
                           struct snd_pcm_substream **rsubstream)
@@ -2030,6 +2055,11 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
        err = snd_pcm_attach_substream(pcm, stream, file, &substream);
        if (err < 0)
                return err;
+       if (substream->ref_count > 1) {
+               *rsubstream = substream;
+               return 0;
+       }
+
        substream->no_mmap_ctrl = 0;
        err = snd_pcm_hw_constraints_init(substream);
        if (err < 0) {
@@ -2056,6 +2086,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
        return err;
 }
 
+EXPORT_SYMBOL(snd_pcm_open_substream);
+
 static int snd_pcm_open_file(struct file *file,
                             struct snd_pcm *pcm,
                             int stream,
@@ -2073,17 +2105,20 @@ static int snd_pcm_open_file(struct file *file,
        if (err < 0)
                return err;
 
-       pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
-       if (pcm_file == NULL) {
-               snd_pcm_release_substream(substream);
-               return -ENOMEM;
+       if (substream->ref_count > 1)
+               pcm_file = substream->file;
+       else {
+               pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
+               if (pcm_file == NULL) {
+                       snd_pcm_release_substream(substream);
+                       return -ENOMEM;
+               }
+               str = substream->pstr;
+               substream->file = pcm_file;
+               substream->pcm_release = pcm_release_private;
+               pcm_file->substream = substream;
+               snd_pcm_add_file(str, pcm_file);
        }
-       str = substream->pstr;
-       substream->file = pcm_file;
-       substream->pcm_release = pcm_release_private;
-       pcm_file->substream = substream;
-       snd_pcm_add_file(str, pcm_file);
-
        file->private_data = pcm_file;
        *rpcm_file = pcm_file;
        return 0;
@@ -2170,7 +2205,6 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
        pcm_file = file->private_data;
        substream = pcm_file->substream;
        snd_assert(substream != NULL, return -ENXIO);
-       snd_assert(!atomic_read(&substream->runtime->mmap_count), );
        pcm = substream->pcm;
        fasync_helper(-1, file, 0, &substream->runtime->fasync);
        mutex_lock(&pcm->open_mutex);
@@ -2493,7 +2527,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
        return 0;
 }
                
-static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
+static int snd_pcm_common_ioctl1(struct file *file,
+                                struct snd_pcm_substream *substream,
                                 unsigned int cmd, void __user *arg)
 {
        snd_assert(substream != NULL, return -ENXIO);
@@ -2518,7 +2553,7 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
        case SNDRV_PCM_IOCTL_CHANNEL_INFO:
                return snd_pcm_channel_info_user(substream, arg);
        case SNDRV_PCM_IOCTL_PREPARE:
-               return snd_pcm_prepare(substream);
+               return snd_pcm_prepare(substream, file);
        case SNDRV_PCM_IOCTL_RESET:
                return snd_pcm_reset(substream);
        case SNDRV_PCM_IOCTL_START:
@@ -2560,7 +2595,8 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
        return -ENOTTY;
 }
 
-static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
+static int snd_pcm_playback_ioctl1(struct file *file,
+                                  struct snd_pcm_substream *substream,
                                   unsigned int cmd, void __user *arg)
 {
        snd_assert(substream != NULL, return -ENXIO);
@@ -2636,10 +2672,11 @@ static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
                return result < 0 ? result : 0;
        }
        }
-       return snd_pcm_common_ioctl1(substream, cmd, arg);
+       return snd_pcm_common_ioctl1(file, substream, cmd, arg);
 }
 
-static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
+static int snd_pcm_capture_ioctl1(struct file *file,
+                                 struct snd_pcm_substream *substream,
                                  unsigned int cmd, void __user *arg)
 {
        snd_assert(substream != NULL, return -ENXIO);
@@ -2715,7 +2752,7 @@ static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
                return result < 0 ? result : 0;
        }
        }
-       return snd_pcm_common_ioctl1(substream, cmd, arg);
+       return snd_pcm_common_ioctl1(file, substream, cmd, arg);
 }
 
 static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
@@ -2728,7 +2765,8 @@ static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
        if (((cmd >> 8) & 0xff) != 'A')
                return -ENOTTY;
 
-       return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
+       return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
+                                      (void __user *)arg);
 }
 
 static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
@@ -2741,7 +2779,8 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
        if (((cmd >> 8) & 0xff) != 'A')
                return -ENOTTY;
 
-       return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
+       return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
+                                     (void __user *)arg);
 }
 
 int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
@@ -2753,12 +2792,12 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
        fs = snd_enter_user();
        switch (substream->stream) {
        case SNDRV_PCM_STREAM_PLAYBACK:
-               result = snd_pcm_playback_ioctl1(substream,
-                                                cmd, (void __user *)arg);
+               result = snd_pcm_playback_ioctl1(NULL, substream, cmd,
+                                                (void __user *)arg);
                break;
        case SNDRV_PCM_STREAM_CAPTURE:
-               result = snd_pcm_capture_ioctl1(substream,
-                                               cmd, (void __user *)arg);
+               result = snd_pcm_capture_ioctl1(NULL, substream, cmd,
+                                               (void __user *)arg);
                break;
        default:
                result = -EINVAL;
@@ -2768,6 +2807,8 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
        return result;
 }
 
+EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
+
 static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
                            loff_t * offset)
 {
@@ -3134,7 +3175,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
        area->vm_ops = &snd_pcm_vm_ops_data;
        area->vm_private_data = substream;
        area->vm_flags |= VM_RESERVED;
-       atomic_inc(&substream->runtime->mmap_count);
+       atomic_inc(&substream->mmap_count);
        return 0;
 }
 
@@ -3166,9 +3207,11 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
                                (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
                                size, area->vm_page_prot))
                return -EAGAIN;
-       atomic_inc(&substream->runtime->mmap_count);
+       atomic_inc(&substream->mmap_count);
        return 0;
 }
+
+EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
 #endif /* SNDRV_PCM_INFO_MMAP */
 
 /*
@@ -3212,6 +3255,8 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
                return snd_pcm_default_mmap(substream, area);
 }
 
+EXPORT_SYMBOL(snd_pcm_mmap_data);
+
 static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
 {
        struct snd_pcm_file * pcm_file;
index 87b47c9564f78029ad6ceaaaf0e8b700fdcbb5d5..8c15c66eb4aa3a630803d12dfa9f7d34caca818b 100644 (file)
@@ -43,7 +43,7 @@ MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
 MODULE_LICENSE("GPL");
 
 #ifdef CONFIG_SND_OSSEMUL
-static int midi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
+static int midi_map[SNDRV_CARDS];
 static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
 module_param_array(midi_map, int, NULL, 0444);
 MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
@@ -1561,7 +1561,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
        entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
        if (entry) {
                entry->private_data = rmidi;
-               entry->c.text.read_size = 1024;
                entry->c.text.read = snd_rawmidi_proc_info_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
index b9919785180b82fff4b238657f68346ebbea91b5..e7234135641cd9ee97762ffe5b076f290ec04b35 100644 (file)
@@ -291,7 +291,6 @@ register_proc(void)
 
        entry->content = SNDRV_INFO_CONTENT_TEXT;
        entry->private_data = NULL;
-       entry->c.text.read_size = 1024;
        entry->c.text.read = info_read;
        if (snd_info_register(entry) < 0) {
                snd_info_free_entry(entry);
index 20f954bc7aa0c0c98d51f169cfac7f2ca8bed3d0..2f0d8773ac6b6e6c04c8c4100c9d3435767378e2 100644 (file)
@@ -129,25 +129,3 @@ static void __exit alsa_seq_exit(void)
 
 module_init(alsa_seq_init)
 module_exit(alsa_seq_exit)
-
-  /* seq_clientmgr.c */
-EXPORT_SYMBOL(snd_seq_create_kernel_client);
-EXPORT_SYMBOL(snd_seq_delete_kernel_client);
-EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
-EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
-EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
-EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
-EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
-EXPORT_SYMBOL(snd_seq_set_queue_tempo);
-  /* seq_memory.c */
-EXPORT_SYMBOL(snd_seq_expand_var_event);
-EXPORT_SYMBOL(snd_seq_dump_var_event);
-  /* seq_ports.c */
-EXPORT_SYMBOL(snd_seq_event_port_attach);
-EXPORT_SYMBOL(snd_seq_event_port_detach);
-  /* seq_lock.c */
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-/*EXPORT_SYMBOL(snd_seq_sleep_in_lock);*/
-/*EXPORT_SYMBOL(snd_seq_sleep_timeout_in_lock);*/
-EXPORT_SYMBOL(snd_use_lock_sync_helper);
-#endif
index bb15d9ee8842a05c60ae31528b80defe8b3eb4ad..532a660df51dae965ca486b537118d8fe9b93272 100644 (file)
@@ -1714,6 +1714,8 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo)
        return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
 }
 
+EXPORT_SYMBOL(snd_seq_set_queue_tempo);
+
 static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
                                         void __user *arg)
 {
@@ -2264,6 +2266,8 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
        return client->number;
 }
 
+EXPORT_SYMBOL(snd_seq_create_kernel_client);
+
 /* exported to kernel modules */
 int snd_seq_delete_kernel_client(int client)
 {
@@ -2280,6 +2284,7 @@ int snd_seq_delete_kernel_client(int client)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_seq_delete_kernel_client);
 
 /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue
  * and snd_seq_kernel_client_enqueue_blocking
@@ -2328,6 +2333,8 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,
        return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
 }
 
+EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
+
 /*
  * exported, called by kernel clients to enqueue events (with blocking)
  *
@@ -2340,6 +2347,7 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev
        return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
 }
 
+EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
 
 /* 
  * exported, called by kernel clients to dispatch events directly to other
@@ -2376,6 +2384,7 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
        return result;
 }
 
+EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
 
 /*
  * exported, called by kernel clients to perform same functions as with
@@ -2396,6 +2405,7 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
        return result;
 }
 
+EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
 
 /* exported (for OSS emulator) */
 int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait)
@@ -2413,6 +2423,8 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
        return 0;
 }
 
+EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
+
 /*---------------------------------------------------------------------------*/
 
 #ifdef CONFIG_PROC_FS
index d9a3e5a18d6ad0ae3ef60ec3f82e2adedba71315..d812dc886360286ff2e609efe7e1850145bd646e 100644 (file)
@@ -80,7 +80,7 @@ static LIST_HEAD(opslist);
 static int num_ops;
 static DEFINE_MUTEX(ops_mutex);
 #ifdef CONFIG_PROC_FS
-static struct snd_info_entry *info_entry = NULL;
+static struct snd_info_entry *info_entry;
 #endif
 
 /*
@@ -555,7 +555,6 @@ static int __init alsa_seq_device_init(void)
        if (info_entry == NULL)
                return -ENOMEM;
        info_entry->content = SNDRV_INFO_CONTENT_TEXT;
-       info_entry->c.text.read_size = 2048;
        info_entry->c.text.read = snd_seq_device_info;
        if (snd_info_register(info_entry) < 0) {
                snd_info_free_entry(info_entry);
index 2a283a59ea4db15dc744db76d1ffc636d9e51977..e55488d1237cebf9435cbafa03d5b5e93364ff08 100644 (file)
@@ -66,7 +66,7 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
 
 static int ports = 1;
-static int duplex = 0;
+static int duplex;
 
 module_param(ports, int, 0444);
 MODULE_PARM_DESC(ports, "number of ports to be created");
@@ -171,7 +171,9 @@ create_port(int idx, int type)
        pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
        if (duplex)
                pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
-       pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+       pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+               | SNDRV_SEQ_PORT_TYPE_SOFTWARE
+               | SNDRV_SEQ_PORT_TYPE_PORT;
        memset(&pcb, 0, sizeof(pcb));
        pcb.owner = THIS_MODULE;
        pcb.unuse = dummy_unuse;
index acce21afdaa47a84e753fa428282e4dc00533ba4..142e9e6882c9a575e4efa7f2092afab3e20cbcf1 100644 (file)
@@ -34,8 +34,8 @@ static struct snd_info_entry *timer_entry;
 
 
 static struct snd_info_entry * __init
-create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *,
-                                                    struct snd_info_buffer *))
+create_info_entry(char *name, void (*read)(struct snd_info_entry *,
+                                          struct snd_info_buffer *))
 {
        struct snd_info_entry *entry;
 
@@ -43,7 +43,6 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *,
        if (entry == NULL)
                return NULL;
        entry->content = SNDRV_INFO_CONTENT_TEXT;
-       entry->c.text.read_size = size;
        entry->c.text.read = read;
        if (snd_info_register(entry) < 0) {
                snd_info_free_entry(entry);
@@ -55,11 +54,11 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *,
 /* create all our /proc entries */
 int __init snd_seq_info_init(void)
 {
-       queues_entry = create_info_entry("queues", 512 + (256 * SNDRV_SEQ_MAX_QUEUES),
+       queues_entry = create_info_entry("queues",
                                         snd_seq_info_queues_read);
-       clients_entry = create_info_entry("clients", 512 + (256 * SNDRV_SEQ_MAX_CLIENTS),
+       clients_entry = create_info_entry("clients",
                                          snd_seq_info_clients_read);
-       timer_entry = create_info_entry("timer", 1024, snd_seq_info_timer_read);
+       timer_entry = create_info_entry("timer", snd_seq_info_timer_read);
        return 0;
 }
 
index a837a94b2d2a816e7fce833e74115b1f59fcf4da..1a34941d42172b8e1d2cedf0c73caba91f4b63c6 100644 (file)
@@ -44,4 +44,6 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
        }
 }
 
+EXPORT_SYMBOL(snd_use_lock_sync_helper);
+
 #endif
index 40b4f679c80e43d4a476f9de0421164106cd5033..4bffe509f7198a3617e754a21fa0da245d19878b 100644 (file)
@@ -118,6 +118,8 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_seq_dump_var_event);
+
 
 /*
  * exported:
@@ -167,6 +169,7 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
        return err < 0 ? err : newlen;
 }
 
+EXPORT_SYMBOL(snd_seq_expand_var_event);
 
 /*
  * release this cell, free extended data if available
index 9caa1372bece852749bce58dfc373af4a3691b57..1daa5b069c798a06b9e87aeca80ded919b2c1f4c 100644 (file)
@@ -278,6 +278,7 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
        struct seq_midisynth *msynth, *ms;
        struct snd_seq_port_info *port;
        struct snd_rawmidi_info *info;
+       struct snd_rawmidi *rmidi = dev->private_data;
        int newclient = 0;
        unsigned int p, ports;
        struct snd_seq_port_callback pcallbacks;
@@ -320,8 +321,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
                }
                client->seq_client =
                        snd_seq_create_kernel_client(
-                               card, 0, "%s", info->name[0] ?
-                               (const char *)info->name : "External MIDI");
+                               card, 0, "%s", card->shortname[0] ?
+                               (const char *)card->shortname : "External MIDI");
                if (client->seq_client < 0) {
                        kfree(client);
                        mutex_unlock(&register_mutex);
@@ -376,7 +377,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
                if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
                    info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
                        port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
-               port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+               port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+                       | SNDRV_SEQ_PORT_TYPE_HARDWARE
+                       | SNDRV_SEQ_PORT_TYPE_PORT;
                port->midi_channels = 16;
                memset(&pcallbacks, 0, sizeof(pcallbacks));
                pcallbacks.owner = THIS_MODULE;
@@ -387,6 +390,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
                pcallbacks.unuse = midisynth_unuse;
                pcallbacks.event_input = event_process_midi;
                port->kernel = &pcallbacks;
+               if (rmidi->ops && rmidi->ops->get_port_info)
+                       rmidi->ops->get_port_info(rmidi, p, port);
                if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
                        goto __nomem;
                ms->seq_client = client->seq_client;
index 41e078c938cdeadff3fe81c7d6f553a340fb3c87..334579a9f268b692178ee301ec3103c4072d8981 100644 (file)
@@ -221,7 +221,6 @@ static void clear_subscriber_list(struct snd_seq_client *client,
 {
        struct list_head *p, *n;
 
-       down_write(&grp->list_mutex);
        list_for_each_safe(p, n, &grp->list_head) {
                struct snd_seq_subscribers *subs;
                struct snd_seq_client *c;
@@ -259,7 +258,6 @@ static void clear_subscriber_list(struct snd_seq_client *client,
                        snd_seq_client_unlock(c);
                }
        }
-       up_write(&grp->list_mutex);
 }
 
 /* delete port data */
@@ -677,6 +675,7 @@ int snd_seq_event_port_attach(int client,
        return ret;
 }
 
+EXPORT_SYMBOL(snd_seq_event_port_attach);
 
 /*
  * Detach the driver from a port.
@@ -696,3 +695,5 @@ int snd_seq_event_port_detach(int client, int port)
 
        return err;
 }
+
+EXPORT_SYMBOL(snd_seq_event_port_detach);
index f4edec603b8f7036e464d8b91c6782751afa817d..0cfa06c6b81f3418c56c5d56ae6740e4a3a04d67 100644 (file)
@@ -390,7 +390,9 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
        pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
        pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
        pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
-       pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+       pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
+               | SNDRV_SEQ_PORT_TYPE_SOFTWARE
+               | SNDRV_SEQ_PORT_TYPE_PORT;
        pinfo->midi_channels = 16;
        memset(&pcallbacks, 0, sizeof(pcallbacks));
        pcallbacks.owner = THIS_MODULE;
index 108e430b50362dc10f65f97e73ecdc0992d93b62..cd862728346cb03e74abe870f4a997c0e5fa6de7 100644 (file)
@@ -39,6 +39,8 @@
 
 static int major = CONFIG_SND_MAJOR;
 int snd_major;
+EXPORT_SYMBOL(snd_major);
+
 static int cards_limit = 1;
 static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO;
 
@@ -60,6 +62,7 @@ MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
  * modules are loaded manually, this limit number increases, too.
  */
 int snd_ecards_limit;
+EXPORT_SYMBOL(snd_ecards_limit);
 
 static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
 static DEFINE_MUTEX(sound_mutex);
@@ -78,20 +81,17 @@ extern struct class *sound_class;
  */
 void snd_request_card(int card)
 {
-       int locked;
-
        if (! current->fs->root)
                return;
-       read_lock(&snd_card_rwlock);
-       locked = snd_cards_lock & (1 << card);
-       read_unlock(&snd_card_rwlock);
-       if (locked)
+       if (snd_card_locked(card))
                return;
        if (card < 0 || card >= cards_limit)
                return;
        request_module("snd-card-%i", card);
 }
 
+EXPORT_SYMBOL(snd_request_card);
+
 static void snd_request_other(int minor)
 {
        char *str;
@@ -133,6 +133,8 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
        return private_data;
 }
 
+EXPORT_SYMBOL(snd_lookup_minor_data);
+
 static int snd_open(struct inode *inode, struct file *file)
 {
        unsigned int minor = iminor(inode);
@@ -281,6 +283,8 @@ int snd_register_device(int type, struct snd_card *card, int dev,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_register_device);
+
 /**
  * snd_unregister_device - unregister the device on the given card
  * @type: the device type, SNDRV_DEVICE_TYPE_XXX
@@ -321,12 +325,14 @@ int snd_unregister_device(int type, struct snd_card *card, int dev)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_unregister_device);
+
 #ifdef CONFIG_PROC_FS
 /*
  *  INFO PART
  */
 
-static struct snd_info_entry *snd_minor_info_entry = NULL;
+static struct snd_info_entry *snd_minor_info_entry;
 
 static const char *snd_device_type_name(int type)
 {
@@ -381,7 +387,6 @@ int __init snd_minor_info_init(void)
 
        entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
        if (entry) {
-               entry->c.text.read_size = PAGE_SIZE;
                entry->c.text.read = snd_minor_info_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
@@ -446,91 +451,3 @@ static void __exit alsa_sound_exit(void)
 
 module_init(alsa_sound_init)
 module_exit(alsa_sound_exit)
-
-  /* sound.c */
-EXPORT_SYMBOL(snd_major);
-EXPORT_SYMBOL(snd_ecards_limit);
-#if defined(CONFIG_KMOD)
-EXPORT_SYMBOL(snd_request_card);
-#endif
-EXPORT_SYMBOL(snd_register_device);
-EXPORT_SYMBOL(snd_unregister_device);
-EXPORT_SYMBOL(snd_lookup_minor_data);
-#if defined(CONFIG_SND_OSSEMUL)
-EXPORT_SYMBOL(snd_register_oss_device);
-EXPORT_SYMBOL(snd_unregister_oss_device);
-EXPORT_SYMBOL(snd_lookup_oss_minor_data);
-#endif
-  /* memory.c */
-EXPORT_SYMBOL(copy_to_user_fromio);
-EXPORT_SYMBOL(copy_from_user_toio);
-  /* init.c */
-EXPORT_SYMBOL(snd_cards);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
-EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
-#endif
-EXPORT_SYMBOL(snd_card_new);
-EXPORT_SYMBOL(snd_card_disconnect);
-EXPORT_SYMBOL(snd_card_free);
-EXPORT_SYMBOL(snd_card_free_in_thread);
-EXPORT_SYMBOL(snd_card_register);
-EXPORT_SYMBOL(snd_component_add);
-EXPORT_SYMBOL(snd_card_file_add);
-EXPORT_SYMBOL(snd_card_file_remove);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_power_wait);
-#endif
-  /* device.c */
-EXPORT_SYMBOL(snd_device_new);
-EXPORT_SYMBOL(snd_device_register);
-EXPORT_SYMBOL(snd_device_free);
-  /* isadma.c */
-#ifdef CONFIG_ISA_DMA_API
-EXPORT_SYMBOL(snd_dma_program);
-EXPORT_SYMBOL(snd_dma_disable);
-EXPORT_SYMBOL(snd_dma_pointer);
-#endif
-  /* info.c */
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(snd_seq_root);
-EXPORT_SYMBOL(snd_iprintf);
-EXPORT_SYMBOL(snd_info_get_line);
-EXPORT_SYMBOL(snd_info_get_str);
-EXPORT_SYMBOL(snd_info_create_module_entry);
-EXPORT_SYMBOL(snd_info_create_card_entry);
-EXPORT_SYMBOL(snd_info_free_entry);
-EXPORT_SYMBOL(snd_info_register);
-EXPORT_SYMBOL(snd_info_unregister);
-EXPORT_SYMBOL(snd_card_proc_new);
-#endif
-  /* info_oss.c */
-#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
-EXPORT_SYMBOL(snd_oss_info_register);
-#endif
-  /* control.c */
-EXPORT_SYMBOL(snd_ctl_new);
-EXPORT_SYMBOL(snd_ctl_new1);
-EXPORT_SYMBOL(snd_ctl_free_one);
-EXPORT_SYMBOL(snd_ctl_add);
-EXPORT_SYMBOL(snd_ctl_remove);
-EXPORT_SYMBOL(snd_ctl_remove_id);
-EXPORT_SYMBOL(snd_ctl_rename_id);
-EXPORT_SYMBOL(snd_ctl_find_numid);
-EXPORT_SYMBOL(snd_ctl_find_id);
-EXPORT_SYMBOL(snd_ctl_notify);
-EXPORT_SYMBOL(snd_ctl_register_ioctl);
-EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
-#ifdef CONFIG_COMPAT
-EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
-EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
-#endif
-EXPORT_SYMBOL(snd_ctl_elem_read);
-EXPORT_SYMBOL(snd_ctl_elem_write);
-  /* misc.c */
-EXPORT_SYMBOL(release_and_free_resource);
-#ifdef CONFIG_SND_VERBOSE_PRINTK
-EXPORT_SYMBOL(snd_verbose_printk);
-#endif
-#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
-EXPORT_SYMBOL(snd_verbose_printd);
-#endif
index 9055c6de95875d4b199dce59b0db0b1fe5737ed6..74f0fe5a1ba086c3aa5b7d531973eacfd5ecab24 100644 (file)
@@ -58,6 +58,8 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
        return private_data;
 }
 
+EXPORT_SYMBOL(snd_lookup_oss_minor_data);
+
 static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
 {
        int minor;
@@ -158,6 +160,8 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
        return -EBUSY;
 }
 
+EXPORT_SYMBOL(snd_register_oss_device);
+
 int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
 {
        int minor = snd_oss_kernel_minor(type, card, dev);
@@ -197,13 +201,15 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_unregister_oss_device);
+
 /*
  *  INFO PART
  */
 
 #ifdef CONFIG_PROC_FS
 
-static struct snd_info_entry *snd_minor_info_oss_entry = NULL;
+static struct snd_info_entry *snd_minor_info_oss_entry;
 
 static const char *snd_oss_device_type_name(int type)
 {
@@ -252,7 +258,6 @@ int __init snd_minor_info_oss_init(void)
 
        entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
        if (entry) {
-               entry->c.text.read_size = PAGE_SIZE;
                entry->c.text.read = snd_minor_info_oss_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
index cdeeb639b675a3e35a532b68a90443fced7e49f7..78199f58b93a7daf6fc9a53e5f7b1190d977b71a 100644 (file)
@@ -1061,7 +1061,6 @@ static int snd_timer_register_system(void)
 static void snd_timer_proc_read(struct snd_info_entry *entry,
                                struct snd_info_buffer *buffer)
 {
-       unsigned long flags;
        struct snd_timer *timer;
        struct snd_timer_instance *ti;
        struct list_head *p, *q;
@@ -1095,7 +1094,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
                if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
                        snd_iprintf(buffer, " SLAVE");
                snd_iprintf(buffer, "\n");
-               spin_lock_irqsave(&timer->lock, flags);
                list_for_each(q, &timer->open_list_head) {
                        ti = list_entry(q, struct snd_timer_instance, open_list);
                        snd_iprintf(buffer, "  Client %s : %s\n",
@@ -1104,12 +1102,11 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
                                                 SNDRV_TIMER_IFLG_RUNNING)
                                    ? "running" : "stopped");
                }
-               spin_unlock_irqrestore(&timer->lock, flags);
        }
        mutex_unlock(&register_mutex);
 }
 
-static struct snd_info_entry *snd_timer_proc_entry = NULL;
+static struct snd_info_entry *snd_timer_proc_entry;
 
 static void __init snd_timer_proc_init(void)
 {
@@ -1117,7 +1114,6 @@ static void __init snd_timer_proc_init(void)
 
        entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL);
        if (entry != NULL) {
-               entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128;
                entry->c.text.read = snd_timer_proc_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
index ae0df549fac7763843412746622681a1bad1d440..ffeafaf2eccae64956ac2bfd8034257fbb10b92c 100644 (file)
@@ -677,6 +677,10 @@ static int __init alsa_card_dummy_init(void)
                                                         i, NULL, 0);
                if (IS_ERR(device))
                        continue;
+               if (!platform_get_drvdata(device)) {
+                       platform_device_unregister(device);
+                       continue;
+               }
                devices[i] = device;
                cards++;
        }
index 77b06009735df818253aa6a70b39392e476bfc80..d3cbbb04758231940d21f2d43a2caa7bddf164cd 100644 (file)
@@ -253,6 +253,10 @@ static int __init alsa_card_mpu401_init(void)
                                                         i, NULL, 0);
                if (IS_ERR(device))
                        continue;
+               if (!platform_get_drvdata(device)) {
+                       platform_device_unregister(device);
+                       continue;
+               }
                platform_devices[i] = device;
                snd_mpu401_devices++;
        }
index b49a45cbf67a09aa9faf39ae75671dd0f7cad1bf..4bf07ca9b17d625bcfc49b30bc5e13729faf089c 100644 (file)
@@ -58,22 +58,26 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu);
 #define MPU401_ACK             0xfe
 
 /* Build in lowlevel io */
-static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr)
+static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data,
+                             unsigned long addr)
 {
        outb(data, addr);
 }
 
-static unsigned char mpu401_read_port(struct snd_mpu401 *mpu, unsigned long addr)
+static unsigned char mpu401_read_port(struct snd_mpu401 *mpu,
+                                     unsigned long addr)
 {
        return inb(addr);
 }
 
-static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr)
+static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data,
+                             unsigned long addr)
 {
        writeb(data, (void __iomem *)addr);
 }
 
-static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu, unsigned long addr)
+static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu,
+                                     unsigned long addr)
 {
        return readb((void __iomem *)addr);
 }
@@ -86,20 +90,13 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu)
                mpu->read(mpu, MPU401D(mpu));
 #ifdef CONFIG_SND_DEBUG
        if (timeout <= 0)
-               snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu)));
+               snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n",
+                          mpu->read(mpu, MPU401C(mpu)));
 #endif
 }
 
-static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
+static void uart_interrupt_tx(struct snd_mpu401 *mpu)
 {
-       spin_lock(&mpu->input_lock);
-       if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
-               snd_mpu401_uart_input_read(mpu);
-       } else {
-               snd_mpu401_uart_clear_rx(mpu);
-       }
-       spin_unlock(&mpu->input_lock);
-       /* ok. for better Tx performance try do some output when input is done */
        if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
            test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
                spin_lock(&mpu->output_lock);
@@ -108,6 +105,22 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
        }
 }
 
+static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
+{
+       if (mpu->info_flags & MPU401_INFO_INPUT) {
+               spin_lock(&mpu->input_lock);
+               if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
+                       snd_mpu401_uart_input_read(mpu);
+               else
+                       snd_mpu401_uart_clear_rx(mpu);
+               spin_unlock(&mpu->input_lock);
+       }
+       if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
+               /* ok. for better Tx performance try do some output
+                  when input is done */
+               uart_interrupt_tx(mpu);
+}
+
 /**
  * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler
  * @irq: the irq number
@@ -116,7 +129,8 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
  *
  * Processes the interrupt for MPU401-UART i/o.
  */
-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
+                                     struct pt_regs *regs)
 {
        struct snd_mpu401 *mpu = dev_id;
        
@@ -126,6 +140,29 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *reg
        return IRQ_HANDLED;
 }
 
+EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
+
+/**
+ * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler
+ * @irq: the irq number
+ * @dev_id: mpu401 instance
+ * @regs: the reigster
+ *
+ * Processes the interrupt for MPU401-UART output.
+ */
+irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
+                                        struct pt_regs *regs)
+{
+       struct snd_mpu401 *mpu = dev_id;
+       
+       if (mpu == NULL)
+               return IRQ_NONE;
+       uart_interrupt_tx(mpu);
+       return IRQ_HANDLED;
+}
+
+EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx);
+
 /*
  * timer callback
  * reprogram the timer and call the interrupt job
@@ -159,7 +196,8 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
                mpu->timer.expires = 1 + jiffies;
                add_timer(&mpu->timer);
        } 
-       mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : MPU401_MODE_OUTPUT_TIMER;
+       mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
+               MPU401_MODE_OUTPUT_TIMER;
        spin_unlock_irqrestore (&mpu->timer_lock, flags);
 }
 
@@ -172,7 +210,8 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
 
        spin_lock_irqsave (&mpu->timer_lock, flags);
        if (mpu->timer_invoked) {
-               mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : ~MPU401_MODE_OUTPUT_TIMER;
+               mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER :
+                       ~MPU401_MODE_OUTPUT_TIMER;
                if (! mpu->timer_invoked)
                        del_timer(&mpu->timer);
        }
@@ -180,11 +219,12 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
 }
 
 /*
-
+ * send a UART command
+ * return zero if successful, non-zero for some errors
  */
 
 static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
-               int ack)
+                              int ack)
 {
        unsigned long flags;
        int timeout, ok;
@@ -196,11 +236,13 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
        }
        /* ok. standard MPU-401 initialization */
        if (mpu->hardware != MPU401_HW_SB) {
-               for (timeout = 1000; timeout > 0 && !snd_mpu401_output_ready(mpu); timeout--)
+               for (timeout = 1000; timeout > 0 &&
+                            !snd_mpu401_output_ready(mpu); timeout--)
                        udelay(10);
 #ifdef CONFIG_SND_DEBUG
                if (!timeout)
-                       snd_printk("cmd: tx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu)));
+                       snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n",
+                                  mpu->read(mpu, MPU401C(mpu)));
 #endif
        }
        mpu->write(mpu, cmd, MPU401C(mpu));
@@ -215,12 +257,14 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
                }
                if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
                        ok = 1;
-       } else {
+       } else
                ok = 1;
-       }
        spin_unlock_irqrestore(&mpu->input_lock, flags);
        if (!ok) {
-               snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu)));
+               snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx "
+                          "(status = 0x%x, data = 0x%x)\n", cmd, mpu->port,
+                          mpu->read(mpu, MPU401C(mpu)),
+                          mpu->read(mpu, MPU401D(mpu)));
                return 1;
        }
        return 0;
@@ -314,7 +358,8 @@ static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream)
 /*
  * trigger input callback
  */
-static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
+static void
+snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
 {
        unsigned long flags;
        struct snd_mpu401 *mpu;
@@ -322,7 +367,8 @@ static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substrea
 
        mpu = substream->rmidi->private_data;
        if (up) {
-               if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) {
+               if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER,
+                                      &mpu->mode)) {
                        /* first time - flush FIFO */
                        while (max-- > 0)
                                mpu->read(mpu, MPU401D(mpu));
@@ -352,13 +398,11 @@ static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu)
        unsigned char byte;
 
        while (max-- > 0) {
-               if (snd_mpu401_input_avail(mpu)) {
-                       byte = mpu->read(mpu, MPU401D(mpu));
-                       if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
-                               snd_rawmidi_receive(mpu->substream_input, &byte, 1);
-               } else {
+               if (! snd_mpu401_input_avail(mpu))
                        break; /* input not available */
-               }
+               byte = mpu->read(mpu, MPU401D(mpu));
+               if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
+                       snd_rawmidi_receive(mpu->substream_input, &byte, 1);
        }
 }
 
@@ -380,16 +424,16 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
        int max = 256, timeout;
 
        do {
-               if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) {
+               if (snd_rawmidi_transmit_peek(mpu->substream_output,
+                                             &byte, 1) == 1) {
                        for (timeout = 100; timeout > 0; timeout--) {
-                               if (snd_mpu401_output_ready(mpu)) {
-                                       mpu->write(mpu, byte, MPU401D(mpu));
-                                       snd_rawmidi_transmit_ack(mpu->substream_output, 1);
+                               if (snd_mpu401_output_ready(mpu))
                                        break;
-                               }
                        }
                        if (timeout == 0)
                                break;  /* Tx FIFO full - try again later */
+                       mpu->write(mpu, byte, MPU401D(mpu));
+                       snd_rawmidi_transmit_ack(mpu->substream_output, 1);
                } else {
                        snd_mpu401_uart_remove_timer (mpu, 0);
                        break;  /* no other data - leave the tx loop */
@@ -400,7 +444,8 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
 /*
  * output trigger callback
  */
-static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
+static void
+snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
 {
        unsigned long flags;
        struct snd_mpu401 *mpu;
@@ -413,14 +458,16 @@ static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substre
                 * since the output timer might have been removed in
                 * snd_mpu401_uart_output_write().
                 */
-               snd_mpu401_uart_add_timer(mpu, 0);
+               if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
+                       snd_mpu401_uart_add_timer(mpu, 0);
 
                /* output pending data */
                spin_lock_irqsave(&mpu->output_lock, flags);
                snd_mpu401_uart_output_write(mpu);
                spin_unlock_irqrestore(&mpu->output_lock, flags);
        } else {
-               snd_mpu401_uart_remove_timer(mpu, 0);
+               if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
+                       snd_mpu401_uart_remove_timer(mpu, 0);
                clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
        }
 }
@@ -458,7 +505,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
  * @device: the device index, zero-based
  * @hardware: the hardware type, MPU401_HW_XXXX
  * @port: the base address of MPU401 port
- * @integrated: non-zero if the port was already reserved by the chip
+ * @info_flags: bitflags MPU401_INFO_XXX
  * @irq: the irq number, -1 if no interrupt for mpu
  * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved.
  * @rrawmidi: the pointer to store the new rawmidi instance
@@ -473,17 +520,24 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
  */
 int snd_mpu401_uart_new(struct snd_card *card, int device,
                        unsigned short hardware,
-                       unsigned long port, int integrated,
+                       unsigned long port,
+                       unsigned int info_flags,
                        int irq, int irq_flags,
                        struct snd_rawmidi ** rrawmidi)
 {
        struct snd_mpu401 *mpu;
        struct snd_rawmidi *rmidi;
+       int in_enable, out_enable;
        int err;
 
        if (rrawmidi)
                *rrawmidi = NULL;
-       if ((err = snd_rawmidi_new(card, "MPU-401U", device, 1, 1, &rmidi)) < 0)
+       if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT)))
+               info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
+       in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0;
+       out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0;
+       if ((err = snd_rawmidi_new(card, "MPU-401U", device,
+                                  out_enable, in_enable, &rmidi)) < 0)
                return err;
        mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
        if (mpu == NULL) {
@@ -497,23 +551,23 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
        spin_lock_init(&mpu->output_lock);
        spin_lock_init(&mpu->timer_lock);
        mpu->hardware = hardware;
-       if (!integrated) {
+       if (! (info_flags & MPU401_INFO_INTEGRATED)) {
                int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
-               if ((mpu->res = request_region(port, res_size, "MPU401 UART")) == NULL) {
-                       snd_printk(KERN_ERR "mpu401_uart: unable to grab port 0x%lx size %d\n", port, res_size);
+               mpu->res = request_region(port, res_size, "MPU401 UART");
+               if (mpu->res == NULL) {
+                       snd_printk(KERN_ERR "mpu401_uart: "
+                                  "unable to grab port 0x%lx size %d\n",
+                                  port, res_size);
                        snd_device_free(card, rmidi);
                        return -EBUSY;
                }
        }
-       switch (hardware) {
-       case MPU401_HW_AUREAL:
+       if (info_flags & MPU401_INFO_MMIO) {
                mpu->write = mpu401_write_mmio;
                mpu->read = mpu401_read_mmio;
-               break;
-       default:
+       } else {
                mpu->write = mpu401_write_port;
                mpu->read = mpu401_read_port;
-               break;
        }
        mpu->port = port;
        if (hardware == MPU401_HW_PC98II)
@@ -521,30 +575,40 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
        else
                mpu->cport = port + 1;
        if (irq >= 0 && irq_flags) {
-               if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, "MPU401 UART", (void *) mpu)) {
-                       snd_printk(KERN_ERR "mpu401_uart: unable to grab IRQ %d\n", irq);
+               if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags,
+                               "MPU401 UART", (void *) mpu)) {
+                       snd_printk(KERN_ERR "mpu401_uart: "
+                                  "unable to grab IRQ %d\n", irq);
                        snd_device_free(card, rmidi);
                        return -EBUSY;
                }
        }
+       mpu->info_flags = info_flags;
        mpu->irq = irq;
        mpu->irq_flags = irq_flags;
        if (card->shortname[0])
-               snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", card->shortname);
+               snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI",
+                        card->shortname);
        else
-               sprintf(rmidi->name, "MPU-401 MIDI %d-%d", card->number, device);
-       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output);
-       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input);
-       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
-                            SNDRV_RAWMIDI_INFO_INPUT |
-                            SNDRV_RAWMIDI_INFO_DUPLEX;
+               sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device);
+       if (out_enable) {
+               snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+                                   &snd_mpu401_uart_output);
+               rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+       }
+       if (in_enable) {
+               snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                                   &snd_mpu401_uart_input);
+               rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+               if (out_enable)
+                       rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+       }
        mpu->rmidi = rmidi;
        if (rrawmidi)
                *rrawmidi = rmidi;
        return 0;
 }
 
-EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
 EXPORT_SYMBOL(snd_mpu401_uart_new);
 
 /*
index b7a0b42813e1325ec616ab5e2c162f946897d79e..474eed06e70f731768432b9959082eb1f213f9b2 100644 (file)
@@ -770,11 +770,15 @@ static int __init alsa_card_mtpav_init(void)
                return err;
 
        device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0);
-       if (IS_ERR(device)) {
-               platform_driver_unregister(&snd_mtpav_driver);
-               return PTR_ERR(device);
-       }
-       return 0;
+       if (!IS_ERR(device)) {
+               if (platform_get_drvdata(device))
+                       return 0;
+               platform_device_unregister(device);
+               err = -ENODEV;
+       } else
+               err = PTR_ERR(device);
+       platform_driver_unregister(&snd_mtpav_driver);
+       return err;
 }
 
 static void __exit alsa_card_mtpav_exit(void)
index 4f85569767742be4c4e090d5f353e685120939a9..87fe376f38f0c0744a6111195346f5f990daca76 100644 (file)
@@ -316,6 +316,8 @@ void snd_opl3_interrupt(struct snd_hwdep * hw)
        }
 }
 
+EXPORT_SYMBOL(snd_opl3_interrupt);
+
 /*
 
  */
@@ -369,6 +371,8 @@ int snd_opl3_new(struct snd_card *card,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_opl3_new);
+
 int snd_opl3_init(struct snd_opl3 *opl3)
 {
        if (! opl3->command) {
@@ -393,6 +397,8 @@ int snd_opl3_init(struct snd_opl3 *opl3)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_opl3_init);
+
 int snd_opl3_create(struct snd_card *card,
                    unsigned long l_port,
                    unsigned long r_port,
@@ -451,6 +457,8 @@ int snd_opl3_create(struct snd_card *card,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_opl3_create);
+
 int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
 {
        int err;
@@ -468,6 +476,8 @@ int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_opl3_timer_new);
+
 int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
                       int device, int seq_device,
                       struct snd_hwdep ** rhwdep)
@@ -526,17 +536,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
        return 0;
 }
 
-EXPORT_SYMBOL(snd_opl3_interrupt);
-EXPORT_SYMBOL(snd_opl3_new);
-EXPORT_SYMBOL(snd_opl3_init);
-EXPORT_SYMBOL(snd_opl3_create);
-EXPORT_SYMBOL(snd_opl3_timer_new);
 EXPORT_SYMBOL(snd_opl3_hwdep_new);
 
-/* opl3_synth.c */
-EXPORT_SYMBOL(snd_opl3_regmap);
-EXPORT_SYMBOL(snd_opl3_reset);
-
 /*
  *  INIT part
  */
index fccf019a6d85968a5ff8f26953d0f9dba655d654..5fd3a4c956261d562cb2c55ce1849ed32108c533 100644 (file)
@@ -100,7 +100,8 @@ static int snd_opl3_oss_create_port(struct snd_opl3 * opl3)
                                                          SNDRV_SEQ_PORT_CAP_WRITE,
                                                          SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
                                                          SNDRV_SEQ_PORT_TYPE_MIDI_GM |
-                                                         SNDRV_SEQ_PORT_TYPE_SYNTH,
+                                                         SNDRV_SEQ_PORT_TYPE_HARDWARE |
+                                                         SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
                                                          voices, voices,
                                                          name);
        if (opl3->oss_chset->port < 0) {
index 57becf34f43efa83949ef5171d6e8853a515cc70..96762c9d485578799c8a8fb6dbce6bad48f17953 100644 (file)
@@ -203,7 +203,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3)
                                                      SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
                                                      SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
                                                      SNDRV_SEQ_PORT_TYPE_MIDI_GM |
-                                                     SNDRV_SEQ_PORT_TYPE_SYNTH,
+                                                     SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
+                                                     SNDRV_SEQ_PORT_TYPE_HARDWARE |
+                                                     SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
                                                      16, voices,
                                                      name);
        if (opl3->chset->port < 0) {
index 6db503f025b3a79ca5f3c44148fb04e9b3b8ecc2..a4b3543a7118121585c808296f1a5dcbda3635e8 100644 (file)
@@ -58,6 +58,8 @@ char snd_opl3_regmap[MAX_OPL2_VOICES][4] =
        { 0x12, 0x15, 0x00, 0x00 }      /* is selected (only left reg block) */
 };
 
+EXPORT_SYMBOL(snd_opl3_regmap);
+
 /*
  * prototypes
  */
@@ -228,6 +230,7 @@ void snd_opl3_reset(struct snd_opl3 * opl3)
        opl3->rhythm = 0;
 }
 
+EXPORT_SYMBOL(snd_opl3_reset);
 
 static int snd_opl3_play_note(struct snd_opl3 * opl3, struct snd_dm_fm_note * note)
 {
@@ -445,3 +448,4 @@ static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection)
 
        return 0;
 }
+
index 4bc860ae02deecb655b87946ec87ceee54ecfe10..01997f24c895708f19a4851061b42bce57c88b1d 100644 (file)
@@ -43,6 +43,8 @@ void snd_opl4_write(struct snd_opl4 *opl4, u8 reg, u8 value)
        outb(value, opl4->pcm_port + 1);
 }
 
+EXPORT_SYMBOL(snd_opl4_write);
+
 u8 snd_opl4_read(struct snd_opl4 *opl4, u8 reg)
 {
        snd_opl4_wait(opl4);
@@ -52,6 +54,8 @@ u8 snd_opl4_read(struct snd_opl4 *opl4, u8 reg)
        return inb(opl4->pcm_port + 1);
 }
 
+EXPORT_SYMBOL(snd_opl4_read);
+
 void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size)
 {
        unsigned long flags;
@@ -76,6 +80,8 @@ void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size
        spin_unlock_irqrestore(&opl4->reg_lock, flags);
 }
 
+EXPORT_SYMBOL(snd_opl4_read_memory);
+
 void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, int size)
 {
        unsigned long flags;
@@ -100,6 +106,8 @@ void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, i
        spin_unlock_irqrestore(&opl4->reg_lock, flags);
 }
 
+EXPORT_SYMBOL(snd_opl4_write_memory);
+
 static void snd_opl4_enable_opl4(struct snd_opl4 *opl4)
 {
        outb(OPL3_REG_MODE, opl4->fm_port + 2);
@@ -256,10 +264,6 @@ int snd_opl4_create(struct snd_card *card,
        return 0;
 }
 
-EXPORT_SYMBOL(snd_opl4_write);
-EXPORT_SYMBOL(snd_opl4_read);
-EXPORT_SYMBOL(snd_opl4_write_memory);
-EXPORT_SYMBOL(snd_opl4_read_memory);
 EXPORT_SYMBOL(snd_opl4_create);
 
 static int __init alsa_opl4_init(void)
index dc0dcdc6c3139e0fa7a58dd05f407da62f4ba2aa..43d8a2bdd280dc7bdc90e5539a1a9916bf79cba9 100644 (file)
@@ -164,7 +164,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
                                                      SNDRV_SEQ_PORT_CAP_WRITE |
                                                      SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
                                                      SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
-                                                     SNDRV_SEQ_PORT_TYPE_MIDI_GM,
+                                                     SNDRV_SEQ_PORT_TYPE_MIDI_GM |
+                                                     SNDRV_SEQ_PORT_TYPE_HARDWARE |
+                                                     SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
                                                      16, 24,
                                                      "OPL4 Wavetable Port");
        if (opl4->chset->port < 0) {
index c01b4c5118b909b1555d8b7e3c8147468ef393f2..2330fec505daf952deb09041eae0a8f3c305f85e 100644 (file)
@@ -998,6 +998,10 @@ static int __init alsa_card_serial_init(void)
                                                         i, NULL, 0);
                if (IS_ERR(device))
                        continue;
+               if (!platform_get_drvdata(device)) {
+                       platform_device_unregister(device);
+                       continue;
+               }
                devices[i] = device;
                cards++;
        }
index 26eb2499d442667e18ff3229f07551e73606bea1..59171f8200dfb8fd1dd957e5bb37dd273d292b79 100644 (file)
@@ -171,6 +171,10 @@ static int __init alsa_card_virmidi_init(void)
                                                         i, NULL, 0);
                if (IS_ERR(device))
                        continue;
+               if (!platform_get_drvdata(device)) {
+                       platform_device_unregister(device);
+                       continue;
+               }
                devices[i] = device;
                cards++;
        }
index fa4a2b5c2d8d19ea82f2ce0e70e2abf36c7f5003..a60168268dddee8f66eda75dd1d42ac0e6f2fd40 100644 (file)
@@ -70,6 +70,8 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t
        return -EIO;
 }
 
+EXPORT_SYMBOL(snd_vx_check_reg_bit);
+
 /*
  * vx_send_irq_dsp - set command irq bit
  * @num: the requested IRQ type, IRQ_XXX
@@ -465,6 +467,8 @@ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_vx_load_boot_image);
+
 /*
  * vx_test_irq_src - query the source of interrupts
  *
@@ -545,6 +549,7 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
+EXPORT_SYMBOL(snd_vx_irq_handler);
 
 /*
  */
@@ -635,7 +640,7 @@ static void vx_proc_init(struct vx_core *chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "vx-status", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, vx_proc_read);
+               snd_info_set_text_ops(entry, chip, vx_proc_read);
 }
 
 
@@ -657,6 +662,8 @@ int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_vx_dsp_boot);
+
 /**
  * snd_vx_dsp_load - load the DSP image
  */
@@ -705,6 +712,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_vx_dsp_load);
+
 #ifdef CONFIG_PM
 /*
  * suspend
@@ -721,6 +730,8 @@ int snd_vx_suspend(struct vx_core *chip, pm_message_t state)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_vx_suspend);
+
 /*
  * resume
  */
@@ -747,6 +758,7 @@ int snd_vx_resume(struct vx_core *chip)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_vx_resume);
 #endif
 
 /**
@@ -790,6 +802,8 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw,
        return chip;
 }
 
+EXPORT_SYMBOL(snd_vx_create);
+
 /*
  * module entries
  */
@@ -804,19 +818,3 @@ static void __exit alsa_vx_core_exit(void)
 
 module_init(alsa_vx_core_init)
 module_exit(alsa_vx_core_exit)
-
-/*
- * exports
- */
-EXPORT_SYMBOL(snd_vx_check_reg_bit);
-EXPORT_SYMBOL(snd_vx_create);
-EXPORT_SYMBOL(snd_vx_setup_firmware);
-EXPORT_SYMBOL(snd_vx_free_firmware);
-EXPORT_SYMBOL(snd_vx_irq_handler);
-EXPORT_SYMBOL(snd_vx_dsp_boot);
-EXPORT_SYMBOL(snd_vx_dsp_load);
-EXPORT_SYMBOL(snd_vx_load_boot_image);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_vx_suspend);
-EXPORT_SYMBOL(snd_vx_resume);
-#endif
index d837783fb538406d94775eb780df7c98300b6c40..e1920af4501de5b94f6a0808589271445d5942e3 100644 (file)
@@ -250,3 +250,6 @@ void snd_vx_free_firmware(struct vx_core *chip)
 }
 
 #endif /* SND_VX_FW_LOADER */
+
+EXPORT_SYMBOL(snd_vx_setup_firmware);
+EXPORT_SYMBOL(snd_vx_free_firmware);
index edfe76fb007461dc425acd8663e40d8193950174..b60fb1892828c92e0fd8b7aab4fe5ba0c1c7243b 100644 (file)
@@ -106,6 +106,8 @@ int snd_i2c_bus_create(struct snd_card *card, const char *name,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_i2c_bus_create);
+
 int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name,
                          unsigned char addr, struct snd_i2c_device **rdevice)
 {
@@ -124,6 +126,8 @@ int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_i2c_device_create);
+
 int snd_i2c_device_free(struct snd_i2c_device *device)
 {
        if (device->bus)
@@ -134,22 +138,29 @@ int snd_i2c_device_free(struct snd_i2c_device *device)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_i2c_device_free);
+
 int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count)
 {
        return device->bus->ops->sendbytes(device, bytes, count);
 }
 
+EXPORT_SYMBOL(snd_i2c_sendbytes);
 
 int snd_i2c_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count)
 {
        return device->bus->ops->readbytes(device, bytes, count);
 }
 
+EXPORT_SYMBOL(snd_i2c_readbytes);
+
 int snd_i2c_probeaddr(struct snd_i2c_bus *bus, unsigned short addr)
 {
        return bus->ops->probeaddr(bus, addr);
 }
 
+EXPORT_SYMBOL(snd_i2c_probeaddr);
+
 /*
  *  bit-operations
  */
@@ -320,12 +331,6 @@ static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr)
        return err;
 }
 
-EXPORT_SYMBOL(snd_i2c_bus_create);
-EXPORT_SYMBOL(snd_i2c_device_create);
-EXPORT_SYMBOL(snd_i2c_device_free);
-EXPORT_SYMBOL(snd_i2c_sendbytes);
-EXPORT_SYMBOL(snd_i2c_readbytes);
-EXPORT_SYMBOL(snd_i2c_probeaddr);
 
 static int __init alsa_i2c_init(void)
 {
index 746500e0695038d547a0d5bc5b43c4c02487b1d2..b074fdddea55d760477743da8025ed052884e75f 100644 (file)
@@ -517,9 +517,9 @@ static void __devinit snd_uda1341_proc_init(struct snd_card *card, struct l3_cli
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(card, "uda1341", &entry))
-               snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_read);
+               snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read);
        if (! snd_card_proc_new(card, "uda1341-regs", &entry))
-               snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_regs_read);
+               snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read);
 }
 
 /* }}} */
index c19ba2910b72331928c4ebfbea97273d547ace15..42db37552efbde1ae8416ae01f6d3b58aee8454f 100644 (file)
@@ -136,7 +136,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(gus->card, "gusirq", &entry))
-               snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read);
+               snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read);
 }
 
 #endif
index 3c0d27aa08b306a34ad40fc41b470f086b0bc62e..f50c276caee84923f69af67de63ab2fe08206b3f 100644 (file)
@@ -264,10 +264,8 @@ int snd_gf1_mem_init(struct snd_gus_card * gus)
        if (snd_gf1_mem_xalloc(alloc, &block) == NULL)
                return -ENOMEM;
 #ifdef CONFIG_SND_DEBUG
-       if (! snd_card_proc_new(gus->card, "gusmem", &entry)) {
-               snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read);
-               entry->c.text.read_size = 256 * 1024;
-       }
+       if (! snd_card_proc_new(gus->card, "gusmem", &entry))
+               snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read);
 #endif
        return 0;
 }
index 2767cc187ae39ead9a75ec865c098c1552091cad..3e4d4d6edd8b50cda1ec9d3100638475f192fcbc 100644 (file)
@@ -194,7 +194,9 @@ static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx)
                                                   &callbacks,
                                                   SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
                                                   SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
-                                                  SNDRV_SEQ_PORT_TYPE_SYNTH,
+                                                  SNDRV_SEQ_PORT_TYPE_SYNTH |
+                                                  SNDRV_SEQ_PORT_TYPE_HARDWARE |
+                                                  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
                                                   16, 0,
                                                   name);
        if (p->chset->port < 0) {
index 4298d339e786fff55ccd1c090476b0bcf17d9441..866300f2acbbd930cda9d0c92217919b1be58faa 100644 (file)
@@ -70,9 +70,9 @@ static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;     /* 0,1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 0,1,3,5,6,7 */
 static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
                                /* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
-static int midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int midi[SNDRV_CARDS];
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
-static int effect[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int effect[SNDRV_CARDS];
 
 #ifdef SNDRV_STB
 #define PFX "interwave-stb: "
index 6d889052c32c96932ed1484213f3f7382110786c..647a996791e9c0ce297c3fe46bbe89859db92495 100644 (file)
@@ -59,7 +59,7 @@ static long midi_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;/* 0x330,0x300 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 0,1,3,5,9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 1,3,5,6,7 */
-static int opl3sa3_ymode[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 };   /* 0,1,2,3 */ /*SL Added*/
+static int opl3sa3_ymode[SNDRV_CARDS];   /* 0,1,2,3 */ /*SL Added*/
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for OPL3-SA soundcard.");
@@ -221,7 +221,7 @@ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsig
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
 {
        struct snd_card *card;
        unsigned long port;
@@ -489,7 +489,7 @@ static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol)
        chip->master_volume = NULL;
 }
 
-static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
+static int __devinit snd_opl3sa2_mixer(struct snd_opl3sa2 *chip)
 {
        struct snd_card *card = chip->card;
        struct snd_ctl_elem_id id1, id2;
@@ -583,8 +583,8 @@ static int snd_opl3sa2_resume(struct snd_card *card)
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_PNP
-static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
-                                 struct pnp_dev *pdev)
+static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
+                                    struct pnp_dev *pdev)
 {
        struct pnp_resource_table * cfg;
        int err;
@@ -862,7 +862,7 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = {
 };
 #endif /* CONFIG_PNP */
 
-static int __init snd_opl3sa2_nonpnp_probe(struct platform_device *pdev)
+static int __devinit snd_opl3sa2_nonpnp_probe(struct platform_device *pdev)
 {
        struct snd_card *card;
        int err;
index e6bfcf74c1c1b1131376a7a9dcf322875e8d4cf6..283817f2de75945ea9402a02b37afa4c2314fe90 100644 (file)
@@ -967,7 +967,7 @@ static void __init snd_miro_proc_init(struct snd_miro * miro)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(miro->card, "miro", &entry))
-               snd_info_set_text_ops(entry, miro, 1024, snd_miro_proc_read);
+               snd_info_set_text_ops(entry, miro, snd_miro_proc_read);
 }
 
 /*
index c0b8d61b75e712782973aeac756967b8ea7e7c07..658179e86142582a58620d0f5fe4db0ea90605e2 100644 (file)
@@ -131,7 +131,7 @@ snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode)
 
 /*
  */
-static void __init
+static void __devinit
 snd_emu8000_read_wait(struct snd_emu8000 *emu)
 {
        while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
@@ -143,7 +143,7 @@ snd_emu8000_read_wait(struct snd_emu8000 *emu)
 
 /*
  */
-static void __init
+static void __devinit
 snd_emu8000_write_wait(struct snd_emu8000 *emu)
 {
        while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
@@ -156,7 +156,7 @@ snd_emu8000_write_wait(struct snd_emu8000 *emu)
 /*
  * detect a card at the given port
  */
-static int __init
+static int __devinit
 snd_emu8000_detect(struct snd_emu8000 *emu)
 {
        /* Initialise */
@@ -182,7 +182,7 @@ snd_emu8000_detect(struct snd_emu8000 *emu)
 /*
  * intiailize audio channels
  */
-static void __init
+static void __devinit
 init_audio(struct snd_emu8000 *emu)
 {
        int ch;
@@ -223,7 +223,7 @@ init_audio(struct snd_emu8000 *emu)
 /*
  * initialize DMA address
  */
-static void __init
+static void __devinit
 init_dma(struct snd_emu8000 *emu)
 {
        EMU8000_SMALR_WRITE(emu, 0);
@@ -327,7 +327,7 @@ static unsigned short init4[128] /*__devinitdata*/ = {
  * Taken from the oss driver, not obvious from the doc how this
  * is meant to work
  */
-static void __init
+static void __devinit
 send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
 {
        int i;
@@ -349,7 +349,7 @@ send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
  * Send initialization arrays to start up, this just follows the
  * initialisation sequence in the adip.
  */
-static void __init
+static void __devinit
 init_arrays(struct snd_emu8000 *emu)
 {
        send_array(emu, init1, ARRAY_SIZE(init1)/4);
@@ -375,7 +375,7 @@ init_arrays(struct snd_emu8000 *emu)
  * seems that the only way to do this is to use the one channel and keep
  * reallocating between read and write.
  */
-static void __init
+static void __devinit
 size_dram(struct snd_emu8000 *emu)
 {
        int i, size;
@@ -500,7 +500,7 @@ snd_emu8000_init_fm(struct snd_emu8000 *emu)
 /*
  * The main initialization routine.
  */
-static void __init
+static void __devinit
 snd_emu8000_init_hw(struct snd_emu8000 *emu)
 {
        int i;
@@ -1019,7 +1019,7 @@ static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
 /*
  * create and attach mixer elements for WaveTable treble/bass controls
  */
-static int __init
+static int __devinit
 snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
 {
        int i, err = 0;
@@ -1069,7 +1069,7 @@ static int snd_emu8000_dev_free(struct snd_device *device)
 /*
  * initialize and register emu8000 synth device.
  */
-int __init
+int __devinit
 snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
                struct snd_seq_device **awe_ret)
 {
index 80b1cf84a1ae28269b07d73db15fb3cf926815d5..1be16c9700f09cd254117f3a0de9b014997de6f6 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/uaccess.h>
 #include <linux/moduleparam.h>
 
-static int emu8000_reset_addr = 0;
+static int emu8000_reset_addr;
 module_param(emu8000_reset_addr, int, 0444);
 MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)");
 
index 6333f900eaee63ec027d557d359dbea01e7fe8dc..7f7f05fa518afa78cd228b3f9a677215b74a873b 100644 (file)
@@ -85,7 +85,7 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;     /* 0,1,3 */
 static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;     /* 5,6,7 */
 static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #ifdef CONFIG_SND_SB16_CSP
-static int csp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int csp[SNDRV_CARDS];
 #endif
 #ifdef SNDRV_SBAWE_EMU8000
 static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
index 9703c68e4e0803e5c7fe0259b7ec7cff8d46604b..fcd638090a9e036195dc11d1f18057d38e09595a 100644 (file)
@@ -1101,7 +1101,7 @@ static int init_proc_entry(struct snd_sb_csp * p, int device)
        struct snd_info_entry *entry;
        sprintf(name, "cspD%d", device);
        if (! snd_card_proc_new(p->chip->card, name, &entry))
-               snd_info_set_text_ops(entry, p, 1024, info_read);
+               snd_info_set_text_ops(entry, p, info_read);
        return 0;
 }
 
index c549aceea2944ae6a3236301495d443f8dfa5309..0b67edd7ac6edbb1bce8244535881b303b18be54 100644 (file)
 #include <sound/core.h>
 #include <sound/sb.h>
 
-/*
-
- */
 
-irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip)
+irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip)
 {
        struct snd_rawmidi *rmidi;
        int max = 64;
        char byte;
 
-       if (chip == NULL || (rmidi = chip->rmidi) == NULL) {
+       if (!chip)
+               return IRQ_NONE;
+       
+       rmidi = chip->rmidi;
+       if (!rmidi) {
                inb(SBP(chip, DATA_AVAIL));     /* ack interrupt */
                return IRQ_NONE;
        }
+
        spin_lock(&chip->midi_input_lock);
        while (max-- > 0) {
                if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
@@ -59,10 +61,6 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip)
        return IRQ_HANDLED;
 }
 
-/*
-
- */
-
 static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream)
 {
        unsigned long flags;
@@ -252,10 +250,6 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
                snd_sb8dsp_midi_output_write(substream);
 }
 
-/*
-
- */
-
 static struct snd_rawmidi_ops snd_sb8dsp_midi_output =
 {
        .open =         snd_sb8dsp_midi_output_open,
index d2a856f0fde201d20e47da42d3960dea8d6537cd..27271c9446dc669e978ae806ca2fda5d44a8415f 100644 (file)
@@ -897,10 +897,9 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l
        struct snd_rawmidi *rawmidi;
        int err;
 
-#define MPU401_SHARE_HARDWARE  1
        if ((err = snd_mpu401_uart_new(card, devnum,
                                       MPU401_HW_MPU401,
-                                      port, MPU401_SHARE_HARDWARE,
+                                      port, MPU401_INFO_INTEGRATED,
                                       irq, SA_INTERRUPT,
                                       &rawmidi)) == 0) {
                struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data;
index 7ae86f82c3fa8b5852015c137950cedf93cf9322..9eb27082c659f16ca4f80c0ae4329426709285a3 100644 (file)
@@ -50,7 +50,7 @@ static int ics2115_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* 2,9,11,12,15 */
 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;     /* PnP setup */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;          /* 0,1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;          /* 0,1,3,5,6,7 */
-static int use_cs4232_midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; 
+static int use_cs4232_midi[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for WaveFront soundcard.");
index a2081803a8276c22877d5df381ea07a77f7cae55..d37346b12dc0804a045ac40ba348643087ee0745 100644 (file)
@@ -216,14 +216,19 @@ config SND_CS46XX_NEW_DSP
          This works better than the old code, so say Y.
 
 config SND_CS5535AUDIO
-       tristate "CS5535 Audio"
+       tristate "CS5535/CS5536 Audio"
        depends on SND && X86 && !X86_64
        select SND_PCM
        select SND_AC97_CODEC
        help
          Say Y here to include support for audio on CS5535 chips. It is
          referred to as NS CS5535 IO or AMD CS5535 IO companion in
-         various literature.
+         various literature. This driver also supports the CS5536 audio
+         device. However, for both chips, on certain boards, you may
+         need to use ac97_quirk=hp_only if your board has physically 
+         mapped headphone out to master output. If that works for you,
+         send lspci -vvv output to the mailing list so that your board
+         can be identified in the quirks list.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-cs5535audio.
index d05200741ac3767538b0c91efe75829619f9ad73..0abf2808d59f7e375db77dd2c2f0d23eb07640c3 100644 (file)
@@ -253,6 +253,8 @@ void snd_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short va
        ac97->bus->ops->write(ac97, reg, value);
 }
 
+EXPORT_SYMBOL(snd_ac97_write);
+
 /**
  * snd_ac97_read - read a value from the given register
  * 
@@ -281,6 +283,8 @@ static inline unsigned short snd_ac97_read_cache(struct snd_ac97 *ac97, unsigned
        return ac97->regs[reg];
 }
 
+EXPORT_SYMBOL(snd_ac97_read);
+
 /**
  * snd_ac97_write_cache - write a value on the given register and update the cache
  * @ac97: the ac97 instance
@@ -302,6 +306,8 @@ void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned sh
        mutex_unlock(&ac97->reg_mutex);
 }
 
+EXPORT_SYMBOL(snd_ac97_write_cache);
+
 /**
  * snd_ac97_update - update the value on the given register
  * @ac97: the ac97 instance
@@ -331,6 +337,8 @@ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short va
        return change;
 }
 
+EXPORT_SYMBOL(snd_ac97_update);
+
 /**
  * snd_ac97_update_bits - update the bits on the given register
  * @ac97: the ac97 instance
@@ -356,6 +364,8 @@ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned sho
        return change;
 }
 
+EXPORT_SYMBOL(snd_ac97_update_bits);
+
 /* no lock version - see snd_ac97_updat_bits() */
 int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg,
                                unsigned short mask, unsigned short value)
@@ -563,7 +573,7 @@ AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1)
 };
 
 static const struct snd_kcontrol_new snd_ac97_controls_mic_boost =
-       AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0);
+       AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_MIC, 6, 1, 0);
 
 
 static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"};
@@ -605,7 +615,7 @@ AC97_SINGLE("Simulated Stereo Enhancement", AC97_GENERAL_PURPOSE, 14, 1, 0),
 AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0),
 AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0),
 AC97_ENUM("Mono Output Select", std_enum[2]),
-AC97_ENUM("Mic Select", std_enum[3]),
+AC97_ENUM("Mic Select Capture Switch", std_enum[3]),
 AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0)
 };
 
@@ -1226,7 +1236,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
        ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080;
 
        /* build center controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) {
+       if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) 
+               && !(ac97->flags & AC97_AD_MULTI)) {
                if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0)
                        return err;
                if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0)
@@ -1238,7 +1249,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
        }
 
        /* build LFE controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) {
+       if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1))
+               && !(ac97->flags & AC97_AD_MULTI)) {
                if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0)
                        return err;
                if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0)
@@ -1250,7 +1262,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
        }
 
        /* build surround controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) {
+       if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) 
+               && !(ac97->flags & AC97_AD_MULTI)) {
                /* Surround Master (0x38) is with stereo mutes */
                if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0)
                        return err;
@@ -1335,9 +1348,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
        }
 
        /* build Aux controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
-               if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
-                       return err;
+       if (!(ac97->flags & AC97_HAS_NO_AUX)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
+                       if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
+                               return err;
+               }
        }
 
        /* build PCM controls */
@@ -1682,6 +1697,7 @@ const char *snd_ac97_get_short_name(struct snd_ac97 *ac97)
        return "unknown codec";
 }
 
+EXPORT_SYMBOL(snd_ac97_get_short_name);
 
 /* wait for a while until registers are accessible after RESET
  * return 0 if ok, negative not ready
@@ -1774,6 +1790,8 @@ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_ac97_bus);
+
 /* stop no dev release warning */
 static void ac97_device_release(struct device * dev)
 {
@@ -2117,6 +2135,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_ac97_mixer);
 
 /*
  * Power down the chip.
@@ -2166,6 +2185,8 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
        snd_ac97_powerdown(ac97);
 }
 
+EXPORT_SYMBOL(snd_ac97_suspend);
+
 /*
  * restore ac97 status
  */
@@ -2267,6 +2288,8 @@ __reset_ready:
                snd_ac97_restore_iec958(ac97);
        }
 }
+
+EXPORT_SYMBOL(snd_ac97_resume);
 #endif
 
 
@@ -2590,29 +2613,7 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons
        return 0;
 }
 
-
-/*
- *  Exported symbols
- */
-
-EXPORT_SYMBOL(snd_ac97_write);
-EXPORT_SYMBOL(snd_ac97_read);
-EXPORT_SYMBOL(snd_ac97_write_cache);
-EXPORT_SYMBOL(snd_ac97_update);
-EXPORT_SYMBOL(snd_ac97_update_bits);
-EXPORT_SYMBOL(snd_ac97_get_short_name);
-EXPORT_SYMBOL(snd_ac97_bus);
-EXPORT_SYMBOL(snd_ac97_mixer);
-EXPORT_SYMBOL(snd_ac97_pcm_assign);
-EXPORT_SYMBOL(snd_ac97_pcm_open);
-EXPORT_SYMBOL(snd_ac97_pcm_close);
-EXPORT_SYMBOL(snd_ac97_pcm_double_rate_rules);
 EXPORT_SYMBOL(snd_ac97_tune_hardware);
-EXPORT_SYMBOL(snd_ac97_set_rate);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_ac97_resume);
-EXPORT_SYMBOL(snd_ac97_suspend);
-#endif
 
 /*
  *  INIT part
index 4d9cf37300f75ae8e0f70b786a4566e81bfc4e7c..7f197c780816819425a4e49b018b49b57af527f2 100644 (file)
@@ -464,6 +464,10 @@ int patch_wolfson05(struct snd_ac97 * ac97)
 {
        /* WM9705, WM9710 */
        ac97->build_ops = &patch_wolfson_wm9705_ops;
+#ifdef CONFIG_TOUCHSCREEN_WM9705
+       /* WM9705 touchscreen uses AUX and VIDEO for touch */
+       ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX;
+#endif
        return 0;
 }
 
@@ -1367,6 +1371,13 @@ static void ad18xx_resume(struct snd_ac97 *ac97)
 
        snd_ac97_restore_iec958(ac97);
 }
+
+static void ad1888_resume(struct snd_ac97 *ac97)
+{
+       ad18xx_resume(ac97);
+       snd_ac97_write_cache(ac97, AC97_CODEC_CLASS_REV, 0x8080);
+}
+
 #endif
 
 int patch_ad1819(struct snd_ac97 * ac97)
@@ -1627,6 +1638,7 @@ static const struct snd_kcontrol_new snd_ac97_ad1981x_jack_sense[] = {
  * (SS vendor << 16 | device)
  */
 static unsigned int ad1981_jacks_blacklist[] = {
+       0x10140537, /* Thinkpad T41p */
        0x10140554, /* Thinkpad T42p/R50p */
        0 /* end */
 };
@@ -1839,7 +1851,7 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = {
        .build_post_spdif = patch_ad198x_post_spdif,
        .build_specific = patch_ad1888_specific,
 #ifdef CONFIG_PM
-       .resume = ad18xx_resume,
+       .resume = ad1888_resume,
 #endif
        .update_jacks = ad1888_update_jacks,
 };
@@ -2048,7 +2060,10 @@ int patch_alc650(struct snd_ac97 * ac97)
        /* Enable SPDIF-IN only on Rev.E and above */
        val = snd_ac97_read(ac97, AC97_ALC650_CLOCK);
        /* SPDIF IN with pin 47 */
-       if (ac97->spec.dev_flags)
+       if (ac97->spec.dev_flags &&
+           /* ASUS A6KM requires EAPD */
+           ! (ac97->subsystem_vendor == 0x1043 &&
+              ac97->subsystem_device == 0x1103))
                val |= 0x03; /* enable */
        else
                val &= ~0x03; /* disable */
index 512a3583b0ce91f4b8cc280086431d266932f3f2..f684aa2c0067667a8d1e4e378035e4b3dcb2beb6 100644 (file)
@@ -317,6 +317,8 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_ac97_set_rate);
+
 static unsigned short get_pslots(struct snd_ac97 *ac97, unsigned char *rate_table, unsigned short *spdif_slots)
 {
        if (!ac97_is_audio(ac97))
@@ -550,6 +552,8 @@ int snd_ac97_pcm_assign(struct snd_ac97_bus *bus,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_ac97_pcm_assign);
+
 /**
  * snd_ac97_pcm_open - opens the given AC97 pcm
  * @pcm: the ac97 pcm instance
@@ -633,6 +637,8 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
        return err;
 }
 
+EXPORT_SYMBOL(snd_ac97_pcm_open);
+
 /**
  * snd_ac97_pcm_close - closes the given AC97 pcm
  * @pcm: the ac97 pcm instance
@@ -658,6 +664,8 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_ac97_pcm_close);
+
 static int double_rate_hw_constraint_rate(struct snd_pcm_hw_params *params,
                                          struct snd_pcm_hw_rule *rule)
 {
@@ -709,3 +717,5 @@ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime)
                                  SNDRV_PCM_HW_PARAM_RATE, -1);
        return err;
 }
+
+EXPORT_SYMBOL(snd_ac97_pcm_double_rate_rules);
index 4d523df79cc71e8b95953ca25cf658750be84215..2118df50b9d6123fa8f9fd2d244309cd549715b8 100644 (file)
@@ -433,7 +433,7 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97)
        prefix = ac97_is_audio(ac97) ? "ac97" : "mc97";
        sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num);
        if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) {
-               snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_read);
+               snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read);
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
                        entry = NULL;
@@ -442,10 +442,9 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97)
        ac97->proc = entry;
        sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num);
        if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) {
-               snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_regs_read);
+               snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read);
 #ifdef CONFIG_SND_DEBUG
                entry->mode |= S_IWUSR;
-               entry->c.text.write_size = 1024;
                entry->c.text.write = snd_ac97_proc_regs_write;
 #endif
                if (snd_info_register(entry) < 0) {
index 0fb7b34073129a9db936abe292ae98b26f7a9593..94c26ec0588207b6f95fa2dd16346aa98d9e99f8 100644 (file)
@@ -453,7 +453,7 @@ static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak453
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(card, "ak4531", &entry))
-               snd_info_set_text_ops(entry, ak4531, 1024, snd_ak4531_proc_read);
+               snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read);
 }
 #endif
 
index eece1c7e55a08c2634ec622249f7386ffece63d9..d42bf4570367cc671c20cee60b6a66bcee779a93 100644 (file)
@@ -753,7 +753,7 @@ snd_ad1889_proc_init(struct snd_ad1889 *chip)
        struct snd_info_entry *entry;
 
        if (!snd_card_proc_new(chip->card, chip->card->driver, &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_ad1889_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read);
 }
 
 static struct ac97_quirk ac97_quirks[] = {
index e2dbc2118902bec429105fb2ede1d7616e93e9ae..5dfdbf6657f2a9f7b53d1ce3ae7b48f6d6e0c291 100644 (file)
@@ -49,7 +49,7 @@ MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}");
 static int index = SNDRV_DEFAULT_IDX1; /* Index */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
 static int pcm_channels = 32;
-static int spdif = 0;
+static int spdif;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio.");
@@ -2173,7 +2173,7 @@ static void __devinit snd_ali_proc_init(struct snd_ali *codec)
 {
        struct snd_info_entry *entry;
        if(!snd_card_proc_new(codec->card, "ali5451", &entry))
-               snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read);
+               snd_info_set_text_ops(entry, codec, snd_ali_proc_read);
 }
 
 static int __devinit snd_ali_resources(struct snd_ali *codec)
index 60423b1c678b86fb3278ab11662d837379e9873a..a9f08066459a9122cb8170e04efa026ac49e0f22 100644 (file)
@@ -746,8 +746,8 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
                card->shortname, chip->alt_port, chip->irq);
 
        if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
-                                       gcr+0x30, 1, pci->irq, 0,
-                                       &chip->rmidi)) < 0) {
+                                       gcr+0x30, MPU401_INFO_INTEGRATED,
+                                       pci->irq, 0, &chip->rmidi)) < 0) {
                printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30);
                goto out_err;
        }
index d0f759d86d3d0a7d7013a679c064ad48e6708e74..f18a8c0e4688301105a5553671314d9d6f025c35 100644 (file)
@@ -1504,7 +1504,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp *chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "atiixp", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read);
 }
 #else /* !CONFIG_PROC_FS */
 #define snd_atiixp_proc_init(chip)
index 12a34c39caa7cb81b15331c2643cb565131a3cd2..40739057076b8af1bd8e872202148eece679431a 100644 (file)
@@ -1177,7 +1177,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read);
 }
 #else
 #define snd_atiixp_proc_init(chip)
index 126870ec063a9620cd921943fa08bb3d8b23a7c5..8a3b118989bfcba6703dc969bd167634d6366624 100644 (file)
@@ -261,6 +261,13 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return err;
        }
        snd_vortex_workaround(pci, pcifix[dev]);
+
+       // Card details needed in snd_vortex_midi
+       strcpy(card->driver, CARD_NAME_SHORT);
+       sprintf(card->shortname, "Aureal Vortex %s", CARD_NAME_SHORT);
+       sprintf(card->longname, "%s at 0x%lx irq %i",
+               card->shortname, chip->io, chip->irq);
+
        // (4) Alloc components.
        // ADB pcm.
        if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) {
@@ -323,11 +330,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 #endif
 
        // (5)
-       strcpy(card->driver, CARD_NAME_SHORT);
-       strcpy(card->shortname, CARD_NAME_SHORT);
-       sprintf(card->longname, "%s at 0x%lx irq %i",
-               card->shortname, chip->io, chip->irq);
-
        if ((err = pci_read_config_word(pci, PCI_DEVICE_ID,
                                  &(chip->device))) < 0) {
                snd_card_free(card);
index 873f486b07b88ebaf298bbe1ad9f012eff2ca459..c75d368ea0871c1790455a74c6fbd50212eee5df 100644 (file)
@@ -47,7 +47,7 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
        struct snd_rawmidi *rmidi;
        int temp, mode;
        struct snd_mpu401 *mpu;
-       int port;
+       unsigned long port;
 
 #ifdef VORTEX_MPU401_LEGACY
        /* EnableHardCodedMPU401Port() */
@@ -70,9 +70,6 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
        temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4;
        hwwrite(vortex->mmio, VORTEX_CTRL2, temp);
        hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET);
-       /* Set some kind of mode */
-       if (mode)
-               hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_ENTER_UART);
 
        /* Check if anything is OK. */
        temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
@@ -98,7 +95,8 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
        port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA);
        if ((temp =
             snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
-                                1, 0, 0, &rmidi)) != 0) {
+                                MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO,
+                                0, 0, &rmidi)) != 0) {
                hwwrite(vortex->mmio, VORTEX_CTRL,
                        (hwread(vortex->mmio, VORTEX_CTRL) &
                         ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
@@ -107,6 +105,9 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
        mpu = rmidi->private_data;
        mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD);
 #endif
+       /* Overwrite MIDI name */
+       snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI %d", CARD_NAME_SHORT , vortex->card->number);
+
        vortex->rmidi = rmidi;
        return 0;
 }
index 4534e1882ada6f81c940e462dc005b2f78109a5a..b4151e208b719d60d3b55ec209c1e00a927fae9c 100644 (file)
@@ -66,31 +66,20 @@ static xtalk_gains_t const asXtalkGainsAllChan = {
        0
            //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff
 };
-static xtalk_gains_t const asXtalkGainsZeros = {
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
+static xtalk_gains_t const asXtalkGainsZeros;
 
-static xtalk_dline_t const alXtalkDlineZeros = {
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0
-};
+static xtalk_dline_t const alXtalkDlineZeros;
 static xtalk_dline_t const alXtalkDlineTest = {
        0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0
 };
 
-static xtalk_instate_t const asXtalkInStateZeros = { 0, 0, 0, 0 };
+static xtalk_instate_t const asXtalkInStateZeros;
 static xtalk_instate_t const asXtalkInStateTest =
     { 0xFF80, 0x0080, 0xFFFF, 0x0001 };
-static xtalk_state_t const asXtalkOutStateZeros = {
-       {0, 0, 0, 0},
-       {0, 0, 0, 0},
-       {0, 0, 0, 0},
-       {0, 0, 0, 0},
-       {0, 0, 0, 0}
-};
+static xtalk_state_t const asXtalkOutStateZeros;
+
 static short const sDiamondKLeftEq = 0x401d;
 static short const sDiamondKRightEq = 0x401d;
 static short const sDiamondKLeftXt = 0xF90E;
@@ -162,13 +151,7 @@ static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = {
        {0, 0, 0, 0, 0}
 };
 
-static xtalk_coefs_t const asXtalkCoefsZeros = {
-       {0, 0, 0, 0, 0},
-       {0, 0, 0, 0, 0},
-       {0, 0, 0, 0, 0},
-       {0, 0, 0, 0, 0},
-       {0, 0, 0, 0, 0}
-};
+static xtalk_coefs_t const asXtalkCoefsZeros;
 static xtalk_coefs_t const asXtalkCoefsPipe = {
        {0, 0, 0x0FA0, 0, 0},
        {0, 0, 0x0FA0, 0, 0},
index 52a364524262caa4f3020dc2fc944b7d9b72cf59..6e62dafb66cd5f2725831ead36d3930caf1b8261 100644 (file)
  *  in the first place >:-P}),
  *  I was forced to base this driver on reverse engineering
  *  (3 weeks' worth of evenings filled with driver work).
- *  (and no, I did NOT go the easy way: to pick up a PCI128 for 9 Euros)
+ *  (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros)
  *
  *  The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name
  *  for compatibility reasons) has the following features:
  *
  *  - builtin AC97 conformant codec (SNR over 80dB)
- *    (really AC97 compliant?? I really doubt it when looking
- *    at the mixer register layout)
+ *    Note that "conformant" != "compliant"!! this chip's mixer register layout
+ *    *differs* from the standard AC97 layout:
+ *    they chose to not implement the headphone register (which is not a
+ *    problem since it's merely optional), yet when doing this, they committed
+ *    the grave sin of letting other registers follow immediately instead of
+ *    keeping a headphone dummy register, thereby shifting the mixer register
+ *    addresses illegally. So far unfortunately it looks like the very flexible
+ *    ALSA AC97 support is still not enough to easily compensate for such a
+ *    grave layout violation despite all tweaks and quirks mechanisms it offers.
  *  - builtin genuine OPL3
  *  - full duplex 16bit playback/record at independent sampling rate
  *  - MPU401 (+ legacy address support) FIXME: how to enable legacy addr??
  * 
  * TODO
  *  - test MPU401 MIDI playback etc.
- *  - power management. See e.g. intel8x0 or cs4281.
- *    This would be nice since the chip runs a bit hot, and it's *required*
- *    anyway for proper ACPI power management.
+ *  - add some power micro-management (disable various units of the card
+ *    as long as they're unused). However this requires I/O ports which I
+ *    haven't figured out yet and which thus might not even exist...
+ *    The standard suspend/resume functionality could probably make use of
+ *    some improvement, too...
  *  - figure out what all unknown port bits are responsible for
+ *  - figure out some cleverly evil scheme to possibly make ALSA AC97 code
+ *    fully accept our quite incompatible ""AC97"" mixer and thus save some
+ *    code (but I'm not too optimistic that doing this is possible at all)
  */
 
 #include <sound/driver.h>
@@ -214,6 +226,16 @@ struct snd_azf3328 {
 
        struct pci_dev *pci;
        int irq;
+
+#ifdef CONFIG_PM
+       /* register value containers for power management
+        * Note: not always full I/O range preserved (just like Win driver!) */
+       u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2];
+       u16 saved_regs_io2   [AZF_IO_SIZE_IO2_PM / 2];
+       u16 saved_regs_mpu   [AZF_IO_SIZE_MPU_PM / 2];
+       u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2];
+       u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2];
+#endif
 };
 
 static const struct pci_device_id snd_azf3328_ids[] __devinitdata = {
@@ -317,10 +339,8 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg
        else
                dst_vol_left &= ~0x80;
 
-       do
-       {
-               if (!left_done)
-               {
+       do {
+               if (!left_done) {
                        if (curr_vol_left > dst_vol_left)
                                curr_vol_left--;
                        else
@@ -330,8 +350,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg
                            left_done = 1;
                        outb(curr_vol_left, portbase + 1);
                }
-               if (!right_done)
-               {
+               if (!right_done) {
                        if (curr_vol_right > dst_vol_right)
                                curr_vol_right--;
                        else
@@ -346,8 +365,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg
                }
                if (delay)
                        mdelay(delay);
-       }
-       while ((!left_done) || (!right_done));
+       } while ((!left_done) || (!right_done));
        snd_azf3328_dbgcallleave();
 }
 
@@ -514,15 +532,18 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_info *uinfo)
 {
        static const char * const texts1[] = {
-               "ModemOut1", "ModemOut2"
+               "Mic1", "Mic2"
        };
        static const char * const texts2[] = {
-               "MonoSelectSource1", "MonoSelectSource2"
+               "Mix", "Mic"
        };
        static const char * const texts3[] = {
                 "Mic", "CD", "Video", "Aux",
                "Line", "Mix", "Mix Mono", "Phone"
         };
+       static const char * const texts4[] = {
+               "pre 3D", "post 3D"
+        };
        struct azf3328_mixer_reg reg;
 
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
@@ -531,14 +552,19 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
         uinfo->value.enumerated.items = reg.enum_c;
         if (uinfo->value.enumerated.item > reg.enum_c - 1U)
                 uinfo->value.enumerated.item = reg.enum_c - 1U;
-       if (reg.reg == IDX_MIXER_ADVCTL2)
-       {
-               if (reg.lchan_shift == 8) /* modem out sel */
+       if (reg.reg == IDX_MIXER_ADVCTL2) {
+               switch(reg.lchan_shift) {
+               case 8: /* modem out sel */
                        strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]);
-               else /* mono sel source */
+                       break;
+               case 9: /* mono sel source */
                        strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]);
-       }
-       else
+                       break;
+               case 15: /* PCM Out Path */
+                       strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]);
+                       break;
+               }
+       } else
                strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item]
 );
         return 0;
@@ -554,12 +580,10 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol,
         
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
        val = snd_azf3328_mixer_inw(chip, reg.reg);
-       if (reg.reg == IDX_MIXER_REC_SELECT)
-       {
+       if (reg.reg == IDX_MIXER_REC_SELECT) {
                ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1);
                ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1);
-       }
-       else
+       } else
                ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1);
 
        snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n",
@@ -579,16 +603,13 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
        oreg = snd_azf3328_mixer_inw(chip, reg.reg);
        val = oreg;
-       if (reg.reg == IDX_MIXER_REC_SELECT)
-       {
+       if (reg.reg == IDX_MIXER_REC_SELECT) {
                if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U ||
                ucontrol->value.enumerated.item[1] > reg.enum_c - 1U)
                        return -EINVAL;
                val = (ucontrol->value.enumerated.item[0] << 8) |
                      (ucontrol->value.enumerated.item[1] << 0);
-       }
-       else
-       {
+       } else {
                if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U)
                        return -EINVAL;
                val &= ~((reg.enum_c - 1) << reg.lchan_shift);
@@ -629,13 +650,14 @@ static const struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata
        AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1),
        AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1),
        AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1),
-       AZF3328_MIXER_ENUM("Modem Out Select", IDX_MIXER_ADVCTL2, 2, 8),
-       AZF3328_MIXER_ENUM("Mono Select Source", IDX_MIXER_ADVCTL2, 2, 9),
+       AZF3328_MIXER_ENUM("Mic Select", IDX_MIXER_ADVCTL2, 2, 8),
+       AZF3328_MIXER_ENUM("Mono Output Select", IDX_MIXER_ADVCTL2, 2, 9),
+       AZF3328_MIXER_ENUM("PCM", IDX_MIXER_ADVCTL2, 2, 15), /* PCM Out Path, place in front since it controls *both* 3D and Bass/Treble! */
        AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0),
        AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0),
        AZF3328_MIXER_SWITCH("3D Control - Switch", IDX_MIXER_ADVCTL2, 13, 0),
-       AZF3328_MIXER_VOL_SPECIAL("3D Control - Wide", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */
-       AZF3328_MIXER_VOL_SPECIAL("3D Control - Space", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */
+       AZF3328_MIXER_VOL_SPECIAL("3D Control - Width", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */
+       AZF3328_MIXER_VOL_SPECIAL("3D Control - Depth", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */
 #if MIXER_TESTING
        AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0),
        AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0),
@@ -813,22 +835,18 @@ snd_azf3328_setdmaa(struct snd_azf3328 *chip,
        unsigned int is_running;
 
        snd_azf3328_dbgcallenter();
-       if (do_recording)
-       {
+       if (do_recording) {
                /* access capture registers, i.e. skip playback reg section */
                portbase = chip->codec_port + 0x20;
                is_running = chip->is_recording;
-       }
-       else
-       {
+       } else {
                /* access the playback register section */
                portbase = chip->codec_port + 0x00;
                is_running = chip->is_playing;
        }
 
        /* AZF3328 uses a two buffer pointer DMA playback approach */
-       if (!is_running)
-       {
+       if (!is_running) {
                unsigned long addr_area2;
                unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */
                count_areas = size/2;
@@ -961,6 +979,13 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
                chip->is_playing = 1;
                snd_azf3328_dbgplay("STARTED PLAYBACK\n");
                break;
+       case SNDRV_PCM_TRIGGER_RESUME:
+               snd_azf3328_dbgplay("RESUME PLAYBACK\n");
+               /* resume playback if we were active */
+               if (chip->is_playing)
+                       snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
+                               snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME);
+               break;
        case SNDRV_PCM_TRIGGER_STOP:
                snd_azf3328_dbgplay("STOP PLAYBACK\n");
 
@@ -988,6 +1013,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
                chip->is_playing = 0;
                snd_azf3328_dbgplay("STOPPED PLAYBACK\n");
                break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               snd_azf3328_dbgplay("SUSPEND PLAYBACK\n");
+               /* make sure playback is stopped */
+               snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
+                       snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME);
+               break;
         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
                 break;
@@ -995,6 +1026,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
                snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
                 break;
         default:
+               printk(KERN_ERR "FIXME: unknown trigger mode!\n");
                 return -EINVAL;
        }
        
@@ -1068,6 +1100,13 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
                chip->is_recording = 1;
                snd_azf3328_dbgplay("STARTED CAPTURE\n");
                break;
+       case SNDRV_PCM_TRIGGER_RESUME:
+               snd_azf3328_dbgplay("RESUME CAPTURE\n");
+               /* resume recording if we were active */
+               if (chip->is_recording)
+                       snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
+                               snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME);
+               break;
         case SNDRV_PCM_TRIGGER_STOP:
                snd_azf3328_dbgplay("STOP CAPTURE\n");
 
@@ -1088,6 +1127,12 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
                chip->is_recording = 0;
                snd_azf3328_dbgplay("STOPPED CAPTURE\n");
                break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               snd_azf3328_dbgplay("SUSPEND CAPTURE\n");
+               /* make sure recording is stopped */
+               snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
+                       snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME);
+               break;
         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n");
                 break;
@@ -1095,6 +1140,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
                snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n");
                 break;
         default:
+               printk(KERN_ERR "FIXME: unknown trigger mode!\n");
                 return -EINVAL;
        }
        
@@ -1163,8 +1209,7 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE),
                status);
                
-       if (status & IRQ_TIMER)
-       {
+       if (status & IRQ_TIMER) {
                /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */
                if (chip->timer)
                        snd_timer_interrupt(chip->timer, chip->timer->sticks);
@@ -1174,50 +1219,43 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                spin_unlock(&chip->reg_lock);
                snd_azf3328_dbgplay("azt3328: timer IRQ\n");
        }
-       if (status & IRQ_PLAYBACK)
-       {
+       if (status & IRQ_PLAYBACK) {
                spin_lock(&chip->reg_lock);
                which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE);
                /* ack all IRQ types immediately */
                snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which);
                        spin_unlock(&chip->reg_lock);
 
-               if (chip->pcm && chip->playback_substream)
-               {
+               if (chip->pcm && chip->playback_substream) {
                        snd_pcm_period_elapsed(chip->playback_substream);
                        snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n",
                                which,
                                inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS));
-               }
-               else
+               } else
                        snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");
                if (which & IRQ_PLAY_SOMETHING)
                        snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n");
        }
-       if (status & IRQ_RECORDING)
-       {
+       if (status & IRQ_RECORDING) {
                 spin_lock(&chip->reg_lock);
                which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE);
                /* ack all IRQ types immediately */
                snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which);
                spin_unlock(&chip->reg_lock);
 
-               if (chip->pcm && chip->capture_substream)
-               {
+               if (chip->pcm && chip->capture_substream) {
                        snd_pcm_period_elapsed(chip->capture_substream);
                        snd_azf3328_dbgplay("REC  period done (#%x), @ %x\n",
                                which,
                                inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS));
-               }
-               else
+               } else
                        snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");
                if (which & IRQ_REC_SOMETHING)
                        snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n");
        }
        /* MPU401 has less critical IRQ requirements
         * than timer and playback/recording, right? */
-       if (status & IRQ_MPU401)
-       {
+       if (status & IRQ_MPU401) {
                snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
 
                /* hmm, do we have to ack the IRQ here somehow?
@@ -1511,8 +1549,7 @@ snd_azf3328_timer_start(struct snd_timer *timer)
        snd_azf3328_dbgcallenter();
        chip = snd_timer_chip(timer);
        delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK;
-       if (delay < 49)
-       {
+       if (delay < 49) {
                /* uhoh, that's not good, since user-space won't know about
                 * this timing tweak
                 * (we need to do it to avoid a lockup, though) */
@@ -1766,9 +1803,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                goto out_err;
        }
 
+       card->private_data = chip;
+
        if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401,
-                                       chip->mpu_port, 1, pci->irq, 0,
-                                       &chip->rmidi)) < 0) {
+                                       chip->mpu_port, MPU401_INFO_INTEGRATED,
+                                       pci->irq, 0, &chip->rmidi)) < 0) {
                snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port);
                goto out_err;
        }
@@ -1791,6 +1830,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                }
        }
 
+       opl3->private_data = chip;
+
        sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, chip->codec_port, chip->irq);
 
@@ -1834,11 +1875,80 @@ snd_azf3328_remove(struct pci_dev *pci)
        snd_azf3328_dbgcallleave();
 }
 
+#ifdef CONFIG_PM
+static int
+snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct snd_azf3328 *chip = card->private_data;
+       int reg;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       
+       snd_pcm_suspend_all(chip->pcm);
+
+       for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
+               chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2);
+
+       /* make sure to disable master volume etc. to prevent looping sound */
+       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
+       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
+       
+       for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
+               chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
+               chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
+               chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
+               chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2);
+
+       pci_set_power_state(pci, PCI_D3hot);
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       return 0;
+}
+
+static int
+snd_azf3328_resume(struct pci_dev *pci)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct snd_azf3328 *chip = card->private_data;
+       int reg;
+
+       pci_restore_state(pci);
+       pci_enable_device(pci);
+       pci_set_power_state(pci, PCI_D0);
+       pci_set_master(pci);
+
+       for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
+               outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
+               outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
+               outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
+               outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
+               outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+#endif
+
+
+
+
 static struct pci_driver driver = {
        .name = "AZF3328",
        .id_table = snd_azf3328_ids,
        .probe = snd_azf3328_probe,
        .remove = __devexit_p(snd_azf3328_remove),
+#ifdef CONFIG_PM
+       .suspend = snd_azf3328_suspend,
+       .resume = snd_azf3328_resume,
+#endif
 };
 
 static int __init
index f489bdaf6d40688cdbae526efa752dd497d2730a..b4f3e3cd006bd2f5c1ec5355ef9e71005299eed5 100644 (file)
@@ -5,6 +5,9 @@
 
 /*** main I/O area port indices ***/
 /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
+#define AZF_IO_SIZE_CODEC      0x80
+#define AZF_IO_SIZE_CODEC_PM   0x70
+
 /* the driver initialisation suggests a layout of 4 main areas:
  * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??).
  * And another area from 0x60 to 0x6f (DirectX timer, IRQ management,
@@ -87,7 +90,7 @@
 #define IDX_IO_REC_DMA_CURROFS  0x34 /* PU:0x00000000 */
 #define IDX_IO_REC_SOUNDFORMAT  0x36 /* PU:0x0000 */
 
-/** hmm, what is this I/O area for? MPU401?? (after playback, recording, ???, timer) **/
+/** hmm, what is this I/O area for? MPU401?? or external DAC via I2S?? (after playback, recording, ???, timer) **/
 #define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init, PU:0x0000 */
 /* general */
 #define IDX_IO_42H             0x42 /* PU:0x0001 */
   #define IRQ_UNKNOWN2                 0x0080 /* probably unused */
 #define IDX_IO_66H             0x66    /* writing 0xffff returns 0x0000 */
 #define IDX_IO_SOME_VALUE      0x68    /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */
-#define IDX_IO_6AH             0x6A    /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback!!! maybe power management?? */
+#define IDX_IO_6AH             0x6A    /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */
+  #define IO_6A_PAUSE_PLAYBACK         0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */
 #define IDX_IO_6CH             0x6C
 #define IDX_IO_6EH             0x6E    /* writing 0xffff returns 0x83fe */
 /* further I/O indices not saved/restored, so probably not used */
 
 /*** I/O 2 area port indices ***/
 /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ 
+#define AZF_IO_SIZE_IO2                0x08
+#define AZF_IO_SIZE_IO2_PM     0x06
+
 #define IDX_IO2_LEGACY_ADDR    0x04
   #define LEGACY_SOMETHING             0x01 /* OPL3?? */
   #define LEGACY_JOY                   0x08
 
+#define AZF_IO_SIZE_MPU                0x04
+#define AZF_IO_SIZE_MPU_PM     0x04
+
+#define AZF_IO_SIZE_SYNTH      0x08
+#define AZF_IO_SIZE_SYNTH_PM   0x06
 
 /*** mixer I/O area port indices ***/
 /* (only 0x22 of 0x40 bytes saved/restored by Windows driver)
- * generally spoken: AC97 register index = AZF3328 mixer reg index + 2
- * (in other words: AZF3328 NOT fully AC97 compliant) */
+ * UNFORTUNATELY azf3328 is NOT truly AC97 compliant: see main file intro */
+#define AZF_IO_SIZE_MIXER      0x40
+#define AZF_IO_SIZE_MIXER_PM   0x22
+
   #define MIXER_VOLUME_RIGHT_MASK      0x001f
   #define MIXER_VOLUME_LEFT_MASK       0x1f00
   #define MIXER_MUTE_MASK              0x8000
 #define IDX_MIXER_ADVCTL1       0x1e
   /* unlisted bits are unmodifiable */
   #define MIXER_ADVCTL1_3DWIDTH_MASK   0x000e
-  #define MIXER_ADVCTL1_HIFI3D_MASK    0x0300
-#define IDX_MIXER_ADVCTL2       0x20 /* resembles AC97_GENERAL_PURPOSE reg! */
+  #define MIXER_ADVCTL1_HIFI3D_MASK    0x0300 /* yup, this is missing the high bit that official AC97 contains, plus it doesn't have linear bit value range behaviour but instead acts weirdly (possibly we're dealing with two *different* 3D settings here??) */
+#define IDX_MIXER_ADVCTL2       0x20 /* subset of AC97_GENERAL_PURPOSE reg! */
   /* unlisted bits are unmodifiable */
-  #define MIXER_ADVCTL2_BIT7           0x0080 /* WaveOut 3D Bypass? mutes WaveOut at LineOut */
-  #define MIXER_ADVCTL2_BIT8           0x0100 /* is this Modem Out Select? */
-  #define MIXER_ADVCTL2_BIT9           0x0200 /* Mono Select Source? */
-  #define MIXER_ADVCTL2_BIT13          0x2000 /* 3D enable? */
-  #define MIXER_ADVCTL2_BIT15          0x8000 /* unknown */
+  #define MIXER_ADVCTL2_LPBK           0x0080 /* Loopback mode -- Win driver: "WaveOut3DBypass"? mutes WaveOut at LineOut */
+  #define MIXER_ADVCTL2_MS             0x0100 /* Mic Select 0=Mic1, 1=Mic2 -- Win driver: "ModemOutSelect"?? */
+  #define MIXER_ADVCTL2_MIX            0x0200 /* Mono output select 0=Mix, 1=Mic; Win driver: "MonoSelectSource"?? */
+  #define MIXER_ADVCTL2_3D             0x2000 /* 3D Enhancement 1=on */
+  #define MIXER_ADVCTL2_POP            0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */
   
 #define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown??? */
 
index 9ee07d4aac1e4666c0f30364dede0b3dc594be29..c33642d8d9a11e37e56e762b3342e4d660b8ae5c 100644 (file)
@@ -44,7 +44,7 @@ MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878},"
 static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int digital_rate[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* digital input rate */
+static int digital_rate[SNDRV_CARDS] /* digital input rate */
 static int load_all;   /* allow to load the non-whitelisted cards */
 
 module_param_array(index, int, NULL, 0444);
@@ -781,10 +781,12 @@ static struct pci_device_id snd_bt87x_ids[] __devinitdata = {
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000),
        /* Viewcast Osprey 200 */
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100),
-       /* AVerMedia Studio No. 103, 203, ...? */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000),
        /* Leadtek Winfast tv 2000xp delux */
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000),
+       /* Voodoo TV 200 */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, 32000),
+       /* AVerMedia Studio No. 103, 203, ...? */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000),
        { }
 };
 MODULE_DEVICE_TABLE(pci, snd_bt87x_ids);
index c8131ea92ed6acae43c02b6261270668e26e4e14..9cb66c59f523e50251fe17013f87564347735777 100644 (file)
 #endif
 
 #define ADC_MUX_MASK           0x0000000f      //Mask for ADC Mux
+#define ADC_MUX_PHONE          0x00000001      //Value to select TAD at ADC Mux (Not used)
 #define ADC_MUX_MIC            0x00000002      //Value to select Mic at ADC Mux
 #define ADC_MUX_LINEIN         0x00000004      //Value to select LineIn at ADC Mux
-#define ADC_MUX_PHONE          0x00000001      //Value to select TAD at ADC Mux (Not used)
 #define ADC_MUX_AUX            0x00000008      //Value to select Aux at ADC Mux
 
 #define SET_CHANNEL 0  /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */
@@ -604,6 +604,8 @@ struct snd_ca0106 {
        u32 spdif_bits[4];             /* s/pdif out setup */
        int spdif_enable;
        int capture_source;
+       int i2c_capture_source;
+       u8 i2c_capture_volume[4][2];
        int capture_mic_line_in;
 
        struct snd_dma_buffer buffer;
index fd8bfebfbd541a846a20c908182406e0ce098437..59bf9bd02534a2a78f08651ef3afb2291a39e87c 100644 (file)
@@ -186,8 +186,8 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
         /* New Audigy SE. Has a different DAC. */
         /* SB0570:
          * CTRL:CA0106-DAT
-         * ADC: WM8768GEDS
-         * DAC: WM8775EDS
+         * ADC: WM8775EDS
+         * DAC: WM8768GEDS
          */
         { .serial = 0x100a1102,
           .name   = "Audigy SE [SB0570]",
@@ -195,9 +195,14 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .i2c_adc = 1,
           .spi_dac = 1 } ,
         /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
+        /* SB0438
+         * CTRL:CA0106-DAT
+         * ADC: WM8775SEDS
+         * DAC: CS4382-KQZ
+         */
         { .serial = 0x10091462,
           .name   = "MSI K8N Diamond MB [SB0438]",
-          .gpio_type = 1,
+          .gpio_type = 2,
           .i2c_adc = 1 } ,
         /* Shuttle XPC SD31P which has an onboard Creative Labs
          * Sound Blaster Live! 24-bit EAX
@@ -326,6 +331,7 @@ int snd_ca0106_spi_write(struct snd_ca0106 * emu,
        return 0;
 }
 
+/* The ADC does not support i2c read, so only write is implemented */
 int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
                                u32 reg,
                                u32 value)
@@ -340,6 +346,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
        }
 
        tmp = reg << 25 | value << 16;
+       // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
        /* Not sure what this I2C channel controls. */
        /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
 
@@ -348,8 +355,9 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
 
        for (retry = 0; retry < 10; retry++) {
                /* Send the data to i2c */
-               tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
-               tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+               //tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
+               //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
+               tmp = 0;
                tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
                snd_ca0106_ptr_write(emu, I2C_A, 0, tmp);
 
@@ -1181,7 +1189,7 @@ static unsigned int spi_dac_init[] = {
        0x02ff,
        0x0400,
        0x0520,
-       0x0600,
+       0x0620, /* Set 24 bit. Was 0x0600 */
        0x08ff,
        0x0aff,
        0x0cff,
@@ -1200,6 +1208,22 @@ static unsigned int spi_dac_init[] = {
        0x1400,
 };
 
+static unsigned int i2c_adc_init[][2] = {
+       { 0x17, 0x00 }, /* Reset */
+       { 0x07, 0x00 }, /* Timeout */
+       { 0x0b, 0x22 },  /* Interface control */
+       { 0x0c, 0x22 },  /* Master mode control */
+       { 0x0d, 0x08 },  /* Powerdown control */
+       { 0x0e, 0xcf },  /* Attenuation Left  0x01 = -103dB, 0xff = 24dB */
+       { 0x0f, 0xcf },  /* Attenuation Right 0.5dB steps */
+       { 0x10, 0x7b },  /* ALC Control 1 */
+       { 0x11, 0x00 },  /* ALC Control 2 */
+       { 0x12, 0x32 },  /* ALC Control 3 */
+       { 0x13, 0x00 },  /* Noise gate control */
+       { 0x14, 0xa6 },  /* Limiter control */
+       { 0x15, ADC_MUX_LINEIN },  /* ADC Mixer control */
+};
+
 static int __devinit snd_ca0106_create(struct snd_card *card,
                                         struct pci_dev *pci,
                                         struct snd_ca0106 **rchip)
@@ -1361,7 +1385,12 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
         snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
        chip->capture_source = 3; /* Set CAPTURE_SOURCE */
 
-        if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */
+        if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */
+               /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
+               outl(0x0, chip->port+GPIO);
+               //outl(0x00f0e000, chip->port+GPIO); /* Analog */
+               outl(0x005f5301, chip->port+GPIO); /* Analog */
+       } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */
                /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
                outl(0x0, chip->port+GPIO);
                //outl(0x00f0e000, chip->port+GPIO); /* Analog */
@@ -1379,7 +1408,19 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
        outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */
 
         if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
-               snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
+               int size, n;
+
+               size = ARRAY_SIZE(i2c_adc_init);
+                //snd_printk("I2C:array size=0x%x\n", size);
+               for (n=0; n < size; n++) {
+                       snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]);
+               }
+               for (n=0; n < 4; n++) {
+                       chip->i2c_capture_volume[n][0]= 0xcf;
+                       chip->i2c_capture_volume[n][1]= 0xcf;
+               }
+               chip->i2c_capture_source=2; /* Line in */
+               //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
        }
         if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */
                int size, n;
index 06fe055674fba098aa3a64921d63d8f3208c9f19..146eed70dce6e62a06a32a24d31f6524cb3d1a5e 100644 (file)
@@ -171,6 +171,76 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
         return change;
 }
 
+static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[6] = {
+               "Phone", "Mic", "Line in", "Aux"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 4;
+       if (uinfo->value.enumerated.item > 3)
+                uinfo->value.enumerated.item = 3;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
+       return 0;
+}
+
+static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+       unsigned int source_id;
+       unsigned int ngain, ogain;
+       int change = 0;
+       u32 source;
+       /* If the capture source has changed,
+        * update the capture volume from the cached value
+        * for the particular source.
+        */
+       source_id = ucontrol->value.enumerated.item[0] ;
+       change = (emu->i2c_capture_source != source_id);
+       if (change) {
+               snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
+               ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
+               ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
+               if (ngain != ogain)
+                       snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
+               ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
+               ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
+               if (ngain != ogain)
+                       snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+               source = 1 << source_id;
+               snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
+               emu->i2c_capture_source = source_id;
+       }
+        return change;
+}
+
+static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
+                                              struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[2] = { "Side out", "Line in" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item > 1)
+                uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
 static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
                                               struct snd_ctl_elem_info *uinfo)
 {
@@ -207,16 +277,16 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
        if (change) {
                emu->capture_mic_line_in = val;
                if (val) {
-                       snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */
+                       //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
                        tmp = inl(emu->port+GPIO) & ~0x400;
                        tmp = tmp | 0x400;
                        outl(tmp, emu->port+GPIO);
-                       snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
+                       //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
                } else {
-                       snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */
+                       //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
                        tmp = inl(emu->port+GPIO) & ~0x400;
                        outl(tmp, emu->port+GPIO);
-                       snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
+                       //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
                }
        }
         return change;
@@ -225,12 +295,22 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
 static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata =
 {
        .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name =         "Mic/Line in Capture",
+       .name =         "Shared Mic/Line in Capture Switch",
        .info =         snd_ca0106_capture_mic_line_in_info,
        .get =          snd_ca0106_capture_mic_line_in_get,
        .put =          snd_ca0106_capture_mic_line_in_put
 };
 
+static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata =
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name =         "Shared Line in/Side out Capture Switch",
+       .info =         snd_ca0106_capture_line_in_side_out_info,
+       .get =          snd_ca0106_capture_mic_line_in_get,
+       .put =          snd_ca0106_capture_mic_line_in_put
+};
+
+
 static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_info *uinfo)
 {
@@ -329,15 +409,81 @@ static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
+static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+{
+        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+        uinfo->count = 2;
+        uinfo->value.integer.min = 0;
+        uinfo->value.integer.max = 255;
+        return 0;
+}
+
+static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+       int source_id;
+
+       source_id = kcontrol->private_value;
+
+        ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
+        ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
+        return 0;
+}
+
+static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
+        unsigned int ogain;
+        unsigned int ngain;
+       int source_id;
+       int change = 0;
+
+       source_id = kcontrol->private_value;
+       ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
+       ngain = ucontrol->value.integer.value[0];
+       if (ngain > 0xff)
+               return 0;
+       if (ogain != ngain) {
+               if (emu->i2c_capture_source == source_id)
+                       snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
+               emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
+               change = 1;
+       }
+       ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
+       ngain = ucontrol->value.integer.value[1];
+       if (ngain > 0xff)
+               return 0;
+       if (ogain != ngain) {
+               if (emu->i2c_capture_source == source_id)
+                       snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
+               emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
+               change = 1;
+       }
+
+       return change;
+}
+
 #define CA_VOLUME(xname,chid,reg) \
 {                                                              \
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
-       .info = snd_ca0106_volume_info,                         \
-       .get =          snd_ca0106_volume_get,                  \
-       .put =          snd_ca0106_volume_put,                  \
+       .info =  snd_ca0106_volume_info,                        \
+       .get =   snd_ca0106_volume_get,                         \
+       .put =   snd_ca0106_volume_put,                         \
        .private_value = ((chid) << 8) | (reg)                  \
 }
 
+#define I2C_VOLUME(xname,chid) \
+{                                                              \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
+       .info =  snd_ca0106_i2c_volume_info,                    \
+       .get =   snd_ca0106_i2c_volume_get,                     \
+       .put =   snd_ca0106_i2c_volume_put,                     \
+       .private_value = chid                                   \
+}
+
 
 static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
        CA_VOLUME("Analog Front Playback Volume",
@@ -361,6 +507,11 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
         CA_VOLUME("CAPTURE feedback Playback Volume",
                  1, CAPTURE_CONTROL),
 
+        I2C_VOLUME("Phone Capture Volume", 0),
+        I2C_VOLUME("Mic Capture Volume", 1),
+        I2C_VOLUME("Line in Capture Volume", 2),
+        I2C_VOLUME("Aux Capture Volume", 3),
+
        {
                .access =       SNDRV_CTL_ELEM_ACCESS_READ,
                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
@@ -378,11 +529,18 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
        },
        {
                .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name =         "Capture Source",
+               .name =         "Digital Capture Source",
                .info =         snd_ca0106_capture_source_info,
                .get =          snd_ca0106_capture_source_get,
                .put =          snd_ca0106_capture_source_put
        },
+       {
+               .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name =         "Capture Source",
+               .info =         snd_ca0106_i2c_capture_source_info,
+               .get =          snd_ca0106_i2c_capture_source_get,
+               .put =          snd_ca0106_i2c_capture_source_put
+       },
        {
                .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
                .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -477,7 +635,10 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                        return err;
        }
        if (emu->details->i2c_adc == 1) {
-               err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
+               if (emu->details->gpio_type == 1)
+                       err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
+               else  /* gpio_type == 2 */
+                       err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
                if (err < 0)
                        return err;
        }
index 63757273bfb73971d4e641b4caf59ec42fb205f3..75ca421eb3a19c9d7c63da437a9b7aad7d015f7b 100644 (file)
@@ -431,33 +431,30 @@ int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu)
        struct snd_info_entry *entry;
        
        if(! snd_card_proc_new(emu->card, "iec958", &entry))
-               snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_iec958);
+               snd_info_set_text_ops(entry, emu, snd_ca0106_proc_iec958);
        if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) {
-               snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read32);
                entry->c.text.write = snd_ca0106_proc_reg_write32;
                entry->mode |= S_IWUSR;
        }
        if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry))
-               snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16);
+               snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read16);
        if(! snd_card_proc_new(emu->card, "ca0106_reg8", &entry))
-               snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read8);
+               snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read8);
        if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) {
-               snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1);
                entry->c.text.write = snd_ca0106_proc_reg_write;
                entry->mode |= S_IWUSR;
 //             entry->private_data = emu;
        }
        if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) {
-               snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_ca0106_proc_i2c_write);
                entry->c.text.write = snd_ca0106_proc_i2c_write;
                entry->mode |= S_IWUSR;
 //             entry->private_data = emu;
        }
        if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) 
-               snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read2);
+               snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2);
        return 0;
 }
 
index e5ce2dabd081f28fb3f40e2ef64bc393a5d7a19c..0938c158b5c9f78c270e47117c0ea1cb23136153 100644 (file)
@@ -2121,7 +2121,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = {
        CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
        CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
        CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
-       CMIPCI_DOUBLE("PC Speaker Playnack Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
+       CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
        CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
 };
 
@@ -2602,7 +2602,7 @@ static void __devinit snd_cmipci_proc_init(struct cmipci *cm)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(cm->card, "cmipci", &entry))
-               snd_info_set_text_ops(entry, cm, 1024, snd_cmipci_proc_read);
+               snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read);
 }
 #else /* !CONFIG_PROC_FS */
 static inline void snd_cmipci_proc_init(struct cmipci *cm) {}
@@ -2932,7 +2932,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
        }
 
        integrated_midi = snd_cmipci_read_b(cm, CM_REG_MPU_PCI) != 0xff;
-       if (integrated_midi)
+       if (integrated_midi && mpu_port[dev] == 1)
                iomidi = cm->iobase + CM_REG_MPU_PCI;
        else {
                iomidi = mpu_port[dev];
@@ -2981,7 +2981,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
 
        if (iomidi > 0) {
                if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
-                                              iomidi, integrated_midi,
+                                              iomidi,
+                                              (integrated_midi ?
+                                               MPU401_INFO_INTEGRATED : 0),
                                               cm->irq, 0, &cm->rmidi)) < 0) {
                        printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi);
                }
index b3c94d83450afab7f2ff6c58bfc83cb484df36ed..e77a4ce314b7a5f34ffab7d2828c82ee47a80ff4 100644 (file)
@@ -1184,7 +1184,7 @@ static void __devinit snd_cs4281_proc_init(struct cs4281 * chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "cs4281", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read);
        if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) {
                entry->content = SNDRV_INFO_CONTENT_DATA;
                entry->private_data = chip;
@@ -1379,6 +1379,13 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
        chip->ba0_addr = pci_resource_start(pci, 0);
        chip->ba1_addr = pci_resource_start(pci, 1);
 
+       chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0));
+       chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1));
+       if (!chip->ba0 || !chip->ba1) {
+               snd_cs4281_free(chip);
+               return -ENOMEM;
+       }
+       
        if (request_irq(pci->irq, snd_cs4281_interrupt, SA_INTERRUPT|SA_SHIRQ,
                        "CS4281", chip)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
@@ -1387,13 +1394,6 @@ static int __devinit snd_cs4281_create(struct snd_card *card,
        }
        chip->irq = pci->irq;
 
-       chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0));
-       chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1));
-       if (!chip->ba0 || !chip->ba1) {
-               snd_cs4281_free(chip);
-               return -ENOMEM;
-       }
-       
        tmp = snd_cs4281_chip_init(chip);
        if (tmp) {
                snd_cs4281_free(chip);
index 848d772ae3c6eb2ad76c008651a62f00d68d0f19..772dc52bfeb270a858c256ac8b013d4632e4d6a1 100644 (file)
@@ -48,8 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,Sound Fusion (CS4280)},"
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int thinkpad[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int external_amp[SNDRV_CARDS];
+static int thinkpad[SNDRV_CARDS];
 static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(index, int, NULL, 0444);
index 69dbf542a6de20a62405c7be4916c17ce7241659..5c2114439204154178adce8c5058e4c2f1deebb9 100644 (file)
@@ -2877,14 +2877,15 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
        if (chip->region.idx[0].resource)
                snd_cs46xx_hw_stop(chip);
 
+       if (chip->irq >= 0)
+               free_irq(chip->irq, chip);
+
        for (idx = 0; idx < 5; idx++) {
                struct snd_cs46xx_region *region = &chip->region.idx[idx];
                if (region->remap_addr)
                        iounmap(region->remap_addr);
                release_and_free_resource(region->resource);
        }
-       if (chip->irq >= 0)
-               free_irq(chip->irq, chip);
 
        if (chip->active_ctrl)
                chip->active_ctrl(chip, -chip->amplifier);
index f407d2a5ce3b6a37a1f0f99d26b04cc99985c1ec..5c9711c0265c85eadd11a3958607ef0090f1220c 100644 (file)
@@ -767,7 +767,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
        if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) {
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
-               entry->c.text.read_size = 512;
       
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
@@ -784,7 +783,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = chip;
                entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-               entry->c.text.read_size = 512;
                entry->c.text.read = cs46xx_dsp_proc_symbol_table_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
@@ -797,7 +795,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = chip;
                entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-               entry->c.text.read_size = 512;
                entry->c.text.read = cs46xx_dsp_proc_modules_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
@@ -810,7 +807,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = chip;
                entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-               entry->c.text.read_size = 512;
                entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
@@ -823,7 +819,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = chip;
                entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-               entry->c.text.read_size = 512;
                entry->c.text.read = cs46xx_dsp_proc_sample_dump_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
@@ -836,7 +831,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = chip;
                entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-               entry->c.text.read_size = 512;
                entry->c.text.read = cs46xx_dsp_proc_task_tree_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
@@ -849,7 +843,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = chip;
                entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-               entry->c.text.read_size = 1024;
                entry->c.text.read = cs46xx_dsp_proc_scb_read;
                if (snd_info_register(entry) < 0) {
                        snd_info_free_entry(entry);
index 2c4ee45fe10c3f894ff0c8b9323c5835a11a5ae2..3844d18af19ca00eae8aedf9314b6054f7c8b909 100644 (file)
@@ -267,7 +267,6 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
                        entry->private_data = scb_info;
                        entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
       
-                       entry->c.text.read_size = 512;
                        entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
       
                        if (snd_info_register(entry) < 0) {
index 08d8ee6547d3451ec0baf95b6a3ea7805d970afc..2911a8adc1f2380180033e86139cfc30ae40974a 100644 (file)
@@ -4,5 +4,9 @@
 
 snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o
 
+ifdef CONFIG_PM
+snd-cs5535audio-objs += cs5535audio_pm.o
+endif
+
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o
index 2c1213a35dccf2df58bf0f147a945541ea99ea6b..91c18a11fe87d24eae508ffc0d583512d7228aa5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Driver for audio on multifunction CS5535 companion device
+ * Driver for audio on multifunction CS5535/6 companion device
  * Copyright (C) Jaya Kumar
  *
  * Based on Jaroslav Kysela and Takashi Iwai's examples.
 
 #define DRIVER_NAME "cs5535audio"
 
+static char *ac97_quirk;
+module_param(ac97_quirk, charp, 0444);
+MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds.");
+
+static struct ac97_quirk ac97_quirks[] __devinitdata = {
+#if 0 /* Not yet confirmed if all 5536 boards are HP only */
+       {
+               .subvendor = PCI_VENDOR_ID_AMD, 
+               .subdevice = PCI_DEVICE_ID_AMD_CS5536_AUDIO, 
+               .name = "AMD RDK",     
+               .type = AC97_TUNE_HP_ONLY
+       },
+#endif
+       {}
+};
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " DRIVER_NAME);
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME);
+
 static struct pci_device_id snd_cs5535audio_ids[] __devinitdata = {
-       { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+       { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) },
        {}
 };
 
@@ -90,7 +110,8 @@ static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au,
                udelay(1);
        } while (--timeout);
        if (!timeout)
-               snd_printk(KERN_ERR "Failure reading cs5535 codec\n");
+               snd_printk(KERN_ERR "Failure reading codec reg 0x%x,"
+                                       "Last value=0x%x\n", reg, val);
 
        return (unsigned short) val;
 }
@@ -148,6 +169,8 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
                return err;
        }
 
+       snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
+
        return 0;
 }
 
@@ -347,6 +370,8 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci,
        if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0)
                goto probefail_out;
 
+       card->private_data = cs5535au;
+
        if ((err = snd_cs5535audio_mixer(cs5535au)) < 0)
                goto probefail_out;
 
@@ -383,6 +408,10 @@ static struct pci_driver driver = {
        .id_table = snd_cs5535audio_ids,
        .probe = snd_cs5535audio_probe,
        .remove = __devexit_p(snd_cs5535audio_remove),
+#ifdef CONFIG_PM
+       .suspend = snd_cs5535audio_suspend,
+       .resume = snd_cs5535audio_resume,
+#endif
 };
 
 static int __init alsa_card_cs5535audio_init(void)
index 5e55a1a1ed652e1db56b68df2236cc91784faab0..4fd1f31a6cf9666606c854b3b7931ea1c48a85a6 100644 (file)
@@ -74,6 +74,8 @@
 #define PRM_RDY_STS                    0x00800000
 #define ACC_CODEC_CNTL_WR_CMD          (~0x80000000)
 #define ACC_CODEC_CNTL_RD_CMD          0x80000000
+#define ACC_CODEC_CNTL_LNK_SHUTDOWN    0x00040000
+#define ACC_CODEC_CNTL_LNK_WRM_RST     0x00020000
 #define PRD_JMP                                0x2000
 #define PRD_EOP                                0x4000
 #define PRD_EOT                                0x8000
@@ -88,6 +90,7 @@ struct cs5535audio_dma_ops {
        void (*disable_dma)(struct cs5535audio *cs5535au);
        void (*pause_dma)(struct cs5535audio *cs5535au);
        void (*setup_prd)(struct cs5535audio *cs5535au, u32 prd_addr);
+       u32 (*read_prd)(struct cs5535audio *cs5535au);
        u32 (*read_dma_pntr)(struct cs5535audio *cs5535au);
 };
 
@@ -103,11 +106,14 @@ struct cs5535audio_dma {
        struct snd_pcm_substream *substream;
        unsigned int buf_addr, buf_bytes;
        unsigned int period_bytes, periods;
+       int suspended;
+       u32 saved_prd;
 };
 
 struct cs5535audio {
        struct snd_card *card;
        struct snd_ac97 *ac97;
+       struct snd_pcm *pcm;
        int irq;
        struct pci_dev *pci;
        unsigned long port;
@@ -117,6 +123,8 @@ struct cs5535audio {
        struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS];
 };
 
+int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state);
+int snd_cs5535audio_resume(struct pci_dev *pci);
 int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio);
 
 #endif /* __SOUND_CS5535AUDIO_H */
index 60bb82b2ff473c0cedec1f00b67644a0c6aa8c83..f0a48693d6873040aef15e90ea758ddf8081de98 100644 (file)
@@ -43,7 +43,8 @@ static struct snd_pcm_hardware snd_cs5535audio_playback =
                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                SNDRV_PCM_INFO_MMAP_VALID |
                                SNDRV_PCM_INFO_PAUSE |
-                               SNDRV_PCM_INFO_SYNC_START
+                               SNDRV_PCM_INFO_SYNC_START |
+                               SNDRV_PCM_INFO_RESUME
                                ),
        .formats =              (
                                SNDRV_PCM_FMTBIT_S16_LE
@@ -193,6 +194,11 @@ static void cs5535audio_playback_setup_prd(struct cs5535audio *cs5535au,
        cs_writel(cs5535au, ACC_BM0_PRD, prd_addr);
 }
 
+static u32 cs5535audio_playback_read_prd(struct cs5535audio *cs5535au)
+{
+       return cs_readl(cs5535au, ACC_BM0_PRD);
+}
+
 static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au)
 {
        return cs_readl(cs5535au, ACC_BM0_PNTR);
@@ -219,6 +225,11 @@ static void cs5535audio_capture_setup_prd(struct cs5535audio *cs5535au,
        cs_writel(cs5535au, ACC_BM1_PRD, prd_addr);
 }
 
+static u32 cs5535audio_capture_read_prd(struct cs5535audio *cs5535au)
+{
+       return cs_readl(cs5535au, ACC_BM1_PRD);
+}
+
 static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au)
 {
        return cs_readl(cs5535au, ACC_BM1_PNTR);
@@ -285,9 +296,17 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_START:
                dma->ops->enable_dma(cs5535au);
                break;
+       case SNDRV_PCM_TRIGGER_RESUME:
+               dma->ops->enable_dma(cs5535au);
+               dma->suspended = 0;
+               break;
        case SNDRV_PCM_TRIGGER_STOP:
                dma->ops->disable_dma(cs5535au);
                break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               dma->ops->disable_dma(cs5535au);
+               dma->suspended = 1;
+               break;
        default:
                snd_printk(KERN_ERR "unhandled trigger\n");
                err = -EINVAL;
@@ -375,6 +394,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
         .enable_dma = cs5535audio_playback_enable_dma,
         .disable_dma = cs5535audio_playback_disable_dma,
         .setup_prd = cs5535audio_playback_setup_prd,
+        .read_prd = cs5535audio_playback_read_prd,
         .pause_dma = cs5535audio_playback_pause_dma,
         .read_dma_pntr = cs5535audio_playback_read_dma_pntr,
 };
@@ -384,6 +404,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = {
         .enable_dma = cs5535audio_capture_enable_dma,
         .disable_dma = cs5535audio_capture_disable_dma,
         .setup_prd = cs5535audio_capture_setup_prd,
+        .read_prd = cs5535audio_capture_read_prd,
         .pause_dma = cs5535audio_capture_pause_dma,
         .read_dma_pntr = cs5535audio_capture_read_dma_pntr,
 };
@@ -413,6 +434,7 @@ int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                        snd_dma_pci_data(cs5535au->pci),
                                        64*1024, 128*1024);
+       cs5535au->pcm = pcm;
 
        return 0;
 }
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
new file mode 100644 (file)
index 0000000..aad0e69
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Power management for audio on multifunction CS5535 companion device
+ * Copyright (C) Jaya Kumar
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/asoundef.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include "cs5535audio.h"
+
+static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)
+{
+       /* 
+       we depend on snd_ac97_suspend to tell the
+       AC97 codec to shutdown. the amd spec suggests
+       that the LNK_SHUTDOWN be done at the same time
+       that the codec power-down is issued. instead,
+       we do it just after rather than at the same 
+       time. excluding codec specific build_ops->suspend
+       ac97 powerdown hits:
+       0x8000 EAPD 
+       0x4000 Headphone amplifier 
+       0x0300 ADC & DAC 
+       0x0400 Analog Mixer powerdown (Vref on) 
+       I am not sure if this is the best that we can do.
+       The remainder to be investigated are:
+       - analog mixer (vref off) 0x0800
+       - AC-link powerdown 0x1000
+       - codec internal clock 0x2000
+       */
+
+       /* set LNK_SHUTDOWN to shutdown AC link */
+       cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_SHUTDOWN);
+
+}
+
+int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct cs5535audio *cs5535au = card->private_data;
+       int i;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
+               struct cs5535audio_dma *dma = &cs5535au->dmas[i];
+               if (dma && dma->substream && !dma->suspended) 
+                       dma->saved_prd = dma->ops->read_prd(cs5535au);
+       }
+       snd_pcm_suspend_all(cs5535au->pcm);
+       snd_ac97_suspend(cs5535au->ac97);
+       /* save important regs, then disable aclink in hw */
+       snd_cs5535audio_stop_hardware(cs5535au);
+       pci_disable_device(pci);
+       pci_save_state(pci);
+
+       return 0;
+}
+
+int snd_cs5535audio_resume(struct pci_dev *pci)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct cs5535audio *cs5535au = card->private_data;
+       u32 tmp;
+       int timeout;
+       int i;
+
+       pci_restore_state(pci);
+       pci_enable_device(pci);
+       pci_set_master(pci);
+
+       /* set LNK_WRM_RST to reset AC link */
+       cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST);
+
+       timeout = 50;
+       do {
+               tmp = cs_readl(cs5535au, ACC_CODEC_STATUS);
+               if (tmp & PRM_RDY_STS)
+                       break;
+               udelay(1);
+       } while (--timeout);
+
+       if (!timeout)
+               snd_printk(KERN_ERR "Failure getting AC Link ready\n");
+
+       /* we depend on ac97 to perform the codec power up */
+       snd_ac97_resume(cs5535au->ac97);
+       /* set up rate regs, dma. actual initiation is done in trig */
+       for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) {
+               struct cs5535audio_dma *dma = &cs5535au->dmas[i];
+               if (dma && dma->substream && dma->suspended) {
+                       dma->substream->ops->prepare(dma->substream);
+                       dma->ops->setup_prd(cs5535au, dma->saved_prd);
+               }
+       }
+               
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+       return 0;
+}
+
index 42b11ba1d2108ddba7546e3f48809b03e9ac37df..549673ea14a9ae48cd2eda5b4eebc9c99041223f 100644 (file)
@@ -46,13 +46,13 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS},"
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int extin[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int extout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int extin[SNDRV_CARDS];
+static int extout[SNDRV_CARDS];
 static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
 static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
 static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
-static int enable_ir[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static uint subsystem[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* Force card subsystem model */
+static int enable_ir[SNDRV_CARDS];
+static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
index 6bfa08436efa251b3c93aa77df2cdb539360b6e9..42a358f989c323481fee4f01ea0ac2a1160c0c4e 100644 (file)
@@ -777,14 +777,6 @@ static int snd_emu10k1_dev_free(struct snd_device *device)
 
 static struct snd_emu_chip_details emu_chip_details[] = {
        /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
-       /* Audigy4 SB0400 */
-       {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
-        .driver = "Audigy2", .name = "Audigy 4 [SB0400]", 
-        .id = "Audigy2",
-        .emu10k2_chip = 1,
-        .ca0108_chip = 1,
-        .spk71 = 1,
-        .ac97_chip = 1} ,
        /* Tested by James@superbug.co.uk 3rd July 2005 */
        /* DSP: CA0108-IAT
         * DAC: CS4382-KQ
@@ -799,13 +791,59 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .ca0108_chip = 1,
         .spk71 = 1,
         .ac97_chip = 1} ,
+       /* Audigy4 (Not PRO) SB0610 */
+       /* Tested by James@superbug.co.uk 4th April 2006 */
+       /* A_IOCFG bits
+        * Output
+        * 0: ?
+        * 1: ?
+        * 2: ?
+        * 3: 0 - Digital Out, 1 - Line in
+        * 4: ?
+        * 5: ?
+        * 6: ?
+        * 7: ?
+        * Input
+        * 8: ?
+        * 9: ?
+        * A: Green jack sense (Front)
+        * B: ?
+        * C: Black jack sense (Rear/Side Right)
+        * D: Yellow jack sense (Center/LFE/Side Left)
+        * E: ?
+        * F: ?
+        *
+        * Digital Out/Line in switch using A_IOCFG bit 3 (0x08)
+        * 0 - Digital Out
+        * 1 - Line in
+        */
+       /* Mic input not tested.
+        * Analog CD input not tested
+        * Digital Out not tested.
+        * Line in working.
+        * Audio output 5.1 working. Side outputs not working.
+        */
+       /* DSP: CA10300-IAT LF
+        * DAC: Cirrus Logic CS4382-KQZ
+        * ADC: Philips 1361T
+        * AC97: Sigmatel STAC9750
+        * CA0151: None
+        */
+       {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
+        .driver = "Audigy2", .name = "Audigy 4 [SB0610]", 
+        .id = "Audigy2",
+        .emu10k2_chip = 1,
+        .ca0108_chip = 1,
+        .spk71 = 1,
+        .adc_1361t = 1,  /* 24 bit capture instead of 16bit */
+        .ac97_chip = 1} ,
        /* Audigy 2 ZS Notebook Cardbus card.*/
        /* Tested by James@superbug.co.uk 22th December 2005 */
        /* Audio output 7.1/Headphones working.
         * Digital output working. (AC3 not checked, only PCM)
         * Audio inputs not tested.
         */ 
-       /* DSP: Tiny2
+       /* DSP: Tina2
         * DAC: Wolfson WM8768/WM8568
         * ADC: Wolfson WM8775
         * AC97: None
@@ -1421,16 +1459,3 @@ void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu)
        }
 }
 #endif
-
-/* memory.c */
-EXPORT_SYMBOL(snd_emu10k1_synth_alloc);
-EXPORT_SYMBOL(snd_emu10k1_synth_free);
-EXPORT_SYMBOL(snd_emu10k1_synth_bzero);
-EXPORT_SYMBOL(snd_emu10k1_synth_copy_from_user);
-EXPORT_SYMBOL(snd_emu10k1_memblk_map);
-/* voice.c */
-EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
-EXPORT_SYMBOL(snd_emu10k1_voice_free);
-/* io.c */
-EXPORT_SYMBOL(snd_emu10k1_ptr_read);
-EXPORT_SYMBOL(snd_emu10k1_ptr_write);
index d51290c18167be855d80521d6a03840e129eebbd..0fb27e4be07b058ae5125474b545d0d9f65b87ef 100644 (file)
@@ -1055,8 +1055,7 @@ static int __devinit snd_emu10k1x_proc_init(struct emu10k1x * emu)
        struct snd_info_entry *entry;
        
        if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) {
-               snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_emu10k1x_proc_reg_read);
                entry->c.text.write = snd_emu10k1x_proc_reg_write;
                entry->mode |= S_IWUSR;
                entry->private_data = emu;
index 2a9d12d106801025bd9870b3f94ddfdcae265483..c31f3d0877fa42f5d041a73243d6b6a4b1a669fd 100644 (file)
@@ -777,6 +777,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
        };
        static char *audigy_remove_ctls[] = {
                /* Master/PCM controls on ac97 of Audigy has no effect */
+               /* On the Audigy2 the AC97 playback is piped into
+                * the Philips ADC for 24bit capture */
                "PCM Playback Switch",
                "PCM Playback Volume",
                "Master Mono Playback Switch",
@@ -804,6 +806,47 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                "AMic Playback Volume", "Mic Playback Volume",
                NULL
        };
+       static char *audigy_remove_ctls_1361t_adc[] = {
+               /* On the Audigy2 the AC97 playback is piped into
+                * the Philips ADC for 24bit capture */
+               "PCM Playback Switch",
+               "PCM Playback Volume",
+               "Master Mono Playback Switch",
+               "Master Mono Playback Volume",
+               "Capture Source",
+               "Capture Switch",
+               "Capture Volume",
+               "Mic Capture Volume",
+               "Headphone Playback Switch",
+               "Headphone Playback Volume",
+               "3D Control - Center",
+               "3D Control - Depth",
+               "3D Control - Switch",
+               "Line2 Playback Volume",
+               "Line2 Capture Volume",
+               NULL
+       };
+       static char *audigy_rename_ctls_1361t_adc[] = {
+               "Master Playback Switch", "Master Capture Switch",
+               "Master Playback Volume", "Master Capture Volume",
+               "Wave Master Playback Volume", "Master Playback Volume",
+               "PC Speaker Playback Switch", "PC Speaker Capture Switch",
+               "PC Speaker Playback Volume", "PC Speaker Capture Volume",
+               "Phone Playback Switch", "Phone Capture Switch",
+               "Phone Playback Volume", "Phone Capture Volume",
+               "Mic Playback Switch", "Mic Capture Switch",
+               "Mic Playback Volume", "Mic Capture Volume",
+               "Line Playback Switch", "Line Capture Switch",
+               "Line Playback Volume", "Line Capture Volume",
+               "CD Playback Switch", "CD Capture Switch",
+               "CD Playback Volume", "CD Capture Volume",
+               "Aux Playback Switch", "Aux Capture Switch",
+               "Aux Playback Volume", "Aux Capture Volume",
+               "Video Playback Switch", "Video Capture Switch",
+               "Video Playback Volume", "Video Capture Volume",
+
+               NULL
+       };
 
        if (emu->card_capabilities->ac97_chip) {
                struct snd_ac97_bus *pbus;
@@ -834,7 +877,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                        snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
                        /* set capture source to mic */
                        snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
-                       c = audigy_remove_ctls;
+                       if (emu->card_capabilities->adc_1361t)
+                               c = audigy_remove_ctls_1361t_adc;
+                       else 
+                               c = audigy_remove_ctls;
                } else {
                        /*
                         * Credits for cards based on STAC9758:
@@ -863,11 +909,15 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
        }
 
        if (emu->audigy)
-               c = audigy_rename_ctls;
+               if (emu->card_capabilities->adc_1361t)
+                       c = audigy_rename_ctls_1361t_adc;
+               else
+                       c = audigy_rename_ctls;
        else
                c = emu10k1_rename_ctls;
        for (; *c; c += 2)
                rename_ctl(card, c[0], c[1]);
+
        if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
                rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
                rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
index 90f1c52703a1d9307f12ea460dd89a208c7034a2..b939e03aaedf8bc2a5902e3f21d262f7de13be44 100644 (file)
@@ -532,57 +532,51 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu)
        struct snd_info_entry *entry;
 #ifdef CONFIG_SND_DEBUG
        if (! snd_card_proc_new(emu->card, "io_regs", &entry)) {
-               snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read);
                entry->c.text.write = snd_emu_proc_io_reg_write;
                entry->mode |= S_IWUSR;
        }
        if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) {
-               snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00a);
                entry->c.text.write = snd_emu_proc_ptr_reg_write00;
                entry->mode |= S_IWUSR;
        }
        if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) {
-               snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00b);
                entry->c.text.write = snd_emu_proc_ptr_reg_write00;
                entry->mode |= S_IWUSR;
        }
        if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) {
-               snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20a);
                entry->c.text.write = snd_emu_proc_ptr_reg_write20;
                entry->mode |= S_IWUSR;
        }
        if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) {
-               snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20b);
                entry->c.text.write = snd_emu_proc_ptr_reg_write20;
                entry->mode |= S_IWUSR;
        }
        if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) {
-               snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20c);
-               entry->c.text.write_size = 64;
+               snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20c);
                entry->c.text.write = snd_emu_proc_ptr_reg_write20;
                entry->mode |= S_IWUSR;
        }
 #endif
        
        if (! snd_card_proc_new(emu->card, "emu10k1", &entry))
-               snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read);
+               snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_read);
 
        if (emu->card_capabilities->emu10k2_chip) {
                if (! snd_card_proc_new(emu->card, "spdif-in", &entry))
-                       snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read);
+                       snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_spdif_read);
        }
        if (emu->card_capabilities->ca0151_chip) {
                if (! snd_card_proc_new(emu->card, "capture-rates", &entry))
-                       snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read);
+                       snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_rates_read);
        }
 
        if (! snd_card_proc_new(emu->card, "voices", &entry))
-               snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read);
+               snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_voices_read);
 
        if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) {
                entry->content = SNDRV_INFO_CONTENT_DATA;
@@ -616,7 +610,6 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu)
                entry->content = SNDRV_INFO_CONTENT_TEXT;
                entry->private_data = emu;
                entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/;
-               entry->c.text.read_size = 128*1024;
                entry->c.text.read = snd_emu10k1_proc_acode_read;
        }
        return 0;
index ef5304df8c1184a25c5955f94d6c9132e9ddea51..029e7856c43beaa7d171a22696d95410119b7b43 100644 (file)
@@ -62,6 +62,8 @@ unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, un
        }
 }
 
+EXPORT_SYMBOL(snd_emu10k1_ptr_read);
+
 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
 {
        unsigned int regptr;
@@ -92,6 +94,8 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
        }
 }
 
+EXPORT_SYMBOL(snd_emu10k1_ptr_write);
+
 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, 
                                          unsigned int reg, 
                                          unsigned int chn)
index e7ec98649f044fa858740dc6a4678bf2b9f7c734..4fcaefe5a3c593e14746288b30217e8c01f94e99 100644 (file)
@@ -287,6 +287,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b
        return err;
 }
 
+EXPORT_SYMBOL(snd_emu10k1_memblk_map);
+
 /*
  * page allocation for DMA
  */
@@ -387,6 +389,7 @@ snd_emu10k1_synth_alloc(struct snd_emu10k1 *hw, unsigned int size)
        return (struct snd_util_memblk *)blk;
 }
 
+EXPORT_SYMBOL(snd_emu10k1_synth_alloc);
 
 /*
  * free a synth sample area
@@ -409,6 +412,7 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_emu10k1_synth_free);
 
 /* check new allocation range */
 static void get_single_page_range(struct snd_util_memhdr *hdr,
@@ -540,6 +544,8 @@ int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk
        return 0;
 }
 
+EXPORT_SYMBOL(snd_emu10k1_synth_bzero);
+
 /*
  * copy_from_user(blk + offset, data, size)
  */
@@ -568,3 +574,5 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me
        } while (offset < end_offset);
        return 0;
 }
+
+EXPORT_SYMBOL(snd_emu10k1_synth_copy_from_user);
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h
new file mode 100644 (file)
index 0000000..7ddb5be
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ *  Driver p17v chips
+ *  Version: 0.01
+ *
+ *   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
+ *
+ */
+
+/******************************************************************************/
+/* Audigy2Value Tina (P17V) pointer-offset register set,
+ * accessed through the PTR20 and DATA24 registers  */
+/******************************************************************************/
+
+/* 00 - 07: Not used */
+#define P17V_PLAYBACK_FIFO_PTR 0x08    /* Current playback fifo pointer
+                                        * and number of sound samples in cache.
+                                        */  
+/* 09 - 12: Not used */
+#define P17V_CAPTURE_FIFO_PTR  0x13    /* Current capture fifo pointer
+                                        * and number of sound samples in cache.
+                                        */  
+/* 14 - 17: Not used */
+#define P17V_PB_CHN_SEL                0x18    /* P17v playback channel select */
+#define P17V_SE_SLOT_SEL_L     0x19    /* Sound Engine slot select low */
+#define P17V_SE_SLOT_SEL_H     0x1a    /* Sound Engine slot select high */
+/* 1b - 1f: Not used */
+/* 20 - 2f: Not used */
+/* 30 - 3b: Not used */
+#define P17V_SPI               0x3c    /* SPI interface register */
+#define P17V_I2C_ADDR          0x3d    /* I2C Address */
+#define P17V_I2C_0             0x3e    /* I2C Data */
+#define P17V_I2C_1             0x3f    /* I2C Data */
+
+#define P17V_START_AUDIO       0x40    /* Start Audio bit */
+/* 41 - 47: Reserved */
+#define P17V_START_CAPTURE     0x48    /* Start Capture bit */
+#define P17V_CAPTURE_FIFO_BASE 0x49    /* Record FIFO base address */
+#define P17V_CAPTURE_FIFO_SIZE 0x4a    /* Record FIFO buffer size */
+#define P17V_CAPTURE_FIFO_INDEX        0x4b    /* Record FIFO capture index */
+#define P17V_CAPTURE_VOL_H     0x4c    /* P17v capture volume control */
+#define P17V_CAPTURE_VOL_L     0x4d    /* P17v capture volume control */
+/* 4e - 4f: Not used */
+/* 50 - 5f: Not used */
+#define P17V_SRCSel            0x60    /* SRC48 and SRCMulti sample rate select
+                                        * and output select
+                                        */
+#define P17V_MIXER_AC97_10K1_VOL_L     0x61    /* 10K to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_10K1_VOL_H     0x62    /* 10K to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_P17V_VOL_L     0x63    /* P17V to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_P17V_VOL_H     0x64    /* P17V to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_SRP_REC_VOL_L  0x65    /* SRP Record to Mixer_AC97 input volume control */
+#define P17V_MIXER_AC97_SRP_REC_VOL_H  0x66    /* SRP Record to Mixer_AC97 input volume control */
+/* 67 - 68: Reserved */
+#define P17V_MIXER_Spdif_10K1_VOL_L    0x69    /* 10K to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_10K1_VOL_H    0x6A    /* 10K to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_P17V_VOL_L    0x6B    /* P17V to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_P17V_VOL_H    0x6C    /* P17V to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_SRP_REC_VOL_L 0x6D    /* SRP Record to Mixer_Spdif input volume control */
+#define P17V_MIXER_Spdif_SRP_REC_VOL_H 0x6E    /* SRP Record to Mixer_Spdif input volume control */
+/* 6f - 70: Reserved */
+#define P17V_MIXER_I2S_10K1_VOL_L      0x71    /* 10K to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_10K1_VOL_H      0x72    /* 10K to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_P17V_VOL_L      0x73    /* P17V to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_P17V_VOL_H      0x74    /* P17V to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_SRP_REC_VOL_L   0x75    /* SRP Record to Mixer_I2S input volume control */
+#define P17V_MIXER_I2S_SRP_REC_VOL_H   0x76    /* SRP Record to Mixer_I2S input volume control */
+/* 77 - 78: Reserved */
+#define P17V_MIXER_AC97_ENABLE         0x79    /* Mixer AC97 input audio enable */
+#define P17V_MIXER_SPDIF_ENABLE                0x7A    /* Mixer SPDIF input audio enable */
+#define P17V_MIXER_I2S_ENABLE          0x7B    /* Mixer I2S input audio enable */
+#define P17V_AUDIO_OUT_ENABLE          0x7C    /* Audio out enable */
+#define P17V_MIXER_ATT                 0x7D    /* SRP Mixer Attenuation Select */
+#define P17V_SRP_RECORD_SRR            0x7E    /* SRP Record channel source Select */
+#define P17V_SOFT_RESET_SRP_MIXER      0x7F    /* SRP and mixer soft reset */
+
+#define P17V_AC97_OUT_MASTER_VOL_L     0x80    /* AC97 Output master volume control */
+#define P17V_AC97_OUT_MASTER_VOL_H     0x81    /* AC97 Output master volume control */
+#define P17V_SPDIF_OUT_MASTER_VOL_L    0x82    /* SPDIF Output master volume control */
+#define P17V_SPDIF_OUT_MASTER_VOL_H    0x83    /* SPDIF Output master volume control */
+#define P17V_I2S_OUT_MASTER_VOL_L      0x84    /* I2S Output master volume control */
+#define P17V_I2S_OUT_MASTER_VOL_H      0x85    /* I2S Output master volume control */
+/* 86 - 87: Not used */
+#define P17V_I2S_CHANNEL_SWAP_PHASE_INVERSE    0x88    /* I2S out mono channel swap
+                                                        * and phase inverse */
+#define P17V_SPDIF_CHANNEL_SWAP_PHASE_INVERSE  0x89    /* SPDIF out mono channel swap
+                                                        * and phase inverse */
+/* 8A: Not used */
+#define P17V_SRP_P17V_ESR              0x8B    /* SRP_P17V estimated sample rate and rate lock */
+#define P17V_SRP_REC_ESR               0x8C    /* SRP_REC estimated sample rate and rate lock */
+#define P17V_SRP_BYPASS                        0x8D    /* srps channel bypass and srps bypass */
+/* 8E - 92: Not used */
+#define P17V_I2S_SRC_SEL               0x93    /* I2SIN mode sel */
+
+
+
+
+
+
index 5c43abf03e89860323643a8cfca3551659c4a037..f2d8eb6c89e19c7c02eec693d3ade833526b4a18 100644 (file)
@@ -1,11 +1,7 @@
 /*
  *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
- *  Driver p16v chips
- *  Version: 0.21
- *
- *
- *  This code was initally based on code from ALSA's emu10k1x.c which is:
- *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
+ *  Driver tina2 chips
+ *  Version: 0.1
  *
  *   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
index 56ffb7dc3ee2d5cd009a070007190fbab0e27998..94eca82dd4fc06914b1b698cfcdbc527b99e2d52 100644 (file)
@@ -139,6 +139,8 @@ int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number,
        return result;
 }
 
+EXPORT_SYMBOL(snd_emu10k1_voice_alloc);
+
 int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
                           struct snd_emu10k1_voice *pvoice)
 {
@@ -153,3 +155,5 @@ int snd_emu10k1_voice_free(struct snd_emu10k1 *emu,
        spin_unlock_irqrestore(&emu->voice_lock, flags);
        return 0;
 }
+
+EXPORT_SYMBOL(snd_emu10k1_voice_free);
index ca9e34e88f629a5e42614529dbbaec7e80470dfb..9d46bbee2a406ac14b6eeb4fe52697465888431f 100644 (file)
@@ -1915,7 +1915,7 @@ static void __devinit snd_ensoniq_proc_init(struct ensoniq * ensoniq)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry))
-               snd_info_set_text_ops(entry, ensoniq, 1024, snd_ensoniq_proc_read);
+               snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read);
 }
 
 /*
index 6f9094ca4fb4b8b5780d1d30ca62e41e8d90d0a2..ca6603fe0b112fd72495754510daaf3a0180bbf0 100644 (file)
@@ -1756,7 +1756,8 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci,
                }
        }
        if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
-                               chip->mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) {
+                               chip->mpu_port, MPU401_INFO_INTEGRATED,
+                               chip->irq, 0, &chip->rmidi) < 0) {
                printk(KERN_ERR "es1938: unable to initialize MPU-401\n");
        } else {
                // this line is vital for MIDI interrupt handling on ess-solo1
index 5ff4175c7b6dd6a05ec3b250ea1c04b123b6ee99..bfa0876e715e87922995fc3e425e6bb08e6b1c67 100644 (file)
@@ -132,7 +132,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;  /* Enable this card *
 static int total_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1024 };
 static int pcm_substreams_p[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4 };
 static int pcm_substreams_c[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1 };
-static int clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int clock[SNDRV_CARDS];
 static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
 static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
 #ifdef SUPPORT_JOYSTICK
@@ -2727,7 +2727,8 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
        }
        if (enable_mpu[dev]) {
                if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
-                                              chip->io_port + ESM_MPU401_PORT, 1,
+                                              chip->io_port + ESM_MPU401_PORT,
+                                              MPU401_INFO_INTEGRATED,
                                               chip->irq, 0, &chip->rmidi)) < 0) {
                        printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n");
                }
index d72fc28c580e7ab554be0fb8e63d0591e7a879c3..0afa573dd2441556e8499e7baaeff29b64b868ad 100644 (file)
@@ -56,7 +56,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card *
  *    3 = MediaForte 64-PCR
  *  High 16-bits are video (radio) device number + 1
  */
-static int tea575x_tuner[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 };
+static int tea575x_tuner[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the FM801 soundcard.");
@@ -1448,7 +1448,8 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
                return err;
        }
        if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801,
-                                      FM801_REG(chip, MPU401_DATA), 1,
+                                      FM801_REG(chip, MPU401_DATA),
+                                      MPU401_INFO_INTEGRATED,
                                       chip->irq, 0, &chip->rmidi)) < 0) {
                snd_card_free(card);
                return err;
index ddfb5ff7fb8f804fd6b24af953364c4bede877fd..dbacba6177db8efef14012d2b265ee96baa709d4 100644 (file)
@@ -1,5 +1,5 @@
 snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o
 ifdef CONFIG_PROC_FS
 snd-hda-codec-objs += hda_proc.o
 endif
index 5bee3b5364783dd985f7bd1da94507a50ac284f9..8c2a8174ece182a24f8a0ee2ae6535cb98b73a67 100644 (file)
@@ -86,6 +86,8 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int dire
        return res;
 }
 
+EXPORT_SYMBOL(snd_hda_codec_read);
+
 /**
  * snd_hda_codec_write - send a single command without waiting for response
  * @codec: the HDA codec
@@ -108,6 +110,8 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
        return err;
 }
 
+EXPORT_SYMBOL(snd_hda_codec_write);
+
 /**
  * snd_hda_sequence_write - sequence writes
  * @codec: the HDA codec
@@ -122,6 +126,8 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq)
                snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
 }
 
+EXPORT_SYMBOL(snd_hda_sequence_write);
+
 /**
  * snd_hda_get_sub_nodes - get the range of sub nodes
  * @codec: the HDA codec
@@ -140,6 +146,8 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *sta
        return (int)(parm & 0x7fff);
 }
 
+EXPORT_SYMBOL(snd_hda_get_sub_nodes);
+
 /**
  * snd_hda_get_connections - get connection list
  * @codec: the HDA codec
@@ -256,6 +264,8 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_hda_queue_unsol_event);
+
 /*
  * process queueud unsolicited events
  */
@@ -384,6 +394,7 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_hda_bus_new);
 
 /*
  * find a matching codec preset
@@ -587,6 +598,8 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_hda_codec_new);
+
 /**
  * snd_hda_codec_setup_stream - set up the codec for streaming
  * @codec: the CODEC to set up
@@ -609,6 +622,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
 }
 
+EXPORT_SYMBOL(snd_hda_codec_setup_stream);
 
 /*
  * amp access functions
@@ -1294,6 +1308,7 @@ int snd_hda_build_controls(struct hda_bus *bus)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_hda_build_controls);
 
 /*
  * stream formats
@@ -1382,6 +1397,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
        return val;
 }
 
+EXPORT_SYMBOL(snd_hda_calc_stream_format);
+
 /**
  * snd_hda_query_supported_pcm - query the supported PCM rates and formats
  * @codec: the HDA codec
@@ -1663,6 +1680,7 @@ int snd_hda_build_pcms(struct hda_bus *bus)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_hda_build_pcms);
 
 /**
  * snd_hda_check_board_config - compare the current codec with the config table
@@ -2165,6 +2183,8 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_hda_suspend);
+
 /**
  * snd_hda_resume - resume the codecs
  * @bus: the HDA bus
@@ -2187,6 +2207,8 @@ int snd_hda_resume(struct hda_bus *bus)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_hda_resume);
+
 /**
  * snd_hda_resume_ctls - resume controls in the new control list
  * @codec: the HDA codec
@@ -2246,25 +2268,6 @@ int snd_hda_resume_spdif_in(struct hda_codec *codec)
 }
 #endif
 
-/*
- * symbols exported for controller modules
- */
-EXPORT_SYMBOL(snd_hda_codec_read);
-EXPORT_SYMBOL(snd_hda_codec_write);
-EXPORT_SYMBOL(snd_hda_sequence_write);
-EXPORT_SYMBOL(snd_hda_get_sub_nodes);
-EXPORT_SYMBOL(snd_hda_queue_unsol_event);
-EXPORT_SYMBOL(snd_hda_bus_new);
-EXPORT_SYMBOL(snd_hda_codec_new);
-EXPORT_SYMBOL(snd_hda_codec_setup_stream);
-EXPORT_SYMBOL(snd_hda_calc_stream_format);
-EXPORT_SYMBOL(snd_hda_build_pcms);
-EXPORT_SYMBOL(snd_hda_build_controls);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_hda_suspend);
-EXPORT_SYMBOL(snd_hda_resume);
-#endif
-
 /*
  *  INIT part
  */
index e821d65afa118bfaec97c5effe9730467dbe39a1..4070b5cd9b6bac4e000899a88ff54765a2870e18 100644 (file)
@@ -82,6 +82,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ICH8},"
                         "{ATI, SB450},"
                         "{ATI, SB600},"
+                        "{ATI, RS600},"
                         "{VIA, VT8251},"
                         "{VIA, VT8237A},"
                         "{SiS, SIS966},"
@@ -167,6 +168,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define ULI_PLAYBACK_INDEX     5
 #define ULI_NUM_PLAYBACK       6
 
+/* ATI HDMI has 1 playback and 0 capture */
+#define ATIHDMI_CAPTURE_INDEX  0
+#define ATIHDMI_NUM_CAPTURE    0
+#define ATIHDMI_PLAYBACK_INDEX 0
+#define ATIHDMI_NUM_PLAYBACK   1
+
 /* this number is statically defined for simplicity */
 #define MAX_AZX_DEV            16
 
@@ -331,6 +338,7 @@ struct azx {
 enum {
        AZX_DRIVER_ICH,
        AZX_DRIVER_ATI,
+       AZX_DRIVER_ATIHDMI,
        AZX_DRIVER_VIA,
        AZX_DRIVER_SIS,
        AZX_DRIVER_ULI,
@@ -340,6 +348,7 @@ enum {
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_ATI] = "HDA ATI SB",
+       [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
        [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
        [AZX_DRIVER_SIS] = "HDA SIS966",
        [AZX_DRIVER_ULI] = "HDA ULI M5461",
@@ -1393,10 +1402,10 @@ static int azx_free(struct azx *chip)
                msleep(1);
        }
 
-       if (chip->remap_addr)
-               iounmap(chip->remap_addr);
        if (chip->irq >= 0)
                free_irq(chip->irq, (void*)chip);
+       if (chip->remap_addr)
+               iounmap(chip->remap_addr);
 
        if (chip->bdl.area)
                snd_dma_free_pages(&chip->bdl);
@@ -1495,6 +1504,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                chip->playback_index_offset = ULI_PLAYBACK_INDEX;
                chip->capture_index_offset = ULI_CAPTURE_INDEX;
                break;
+       case AZX_DRIVER_ATIHDMI:
+               chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
+               chip->capture_streams = ATIHDMI_NUM_CAPTURE;
+               chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
+               chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
+               break;
        default:
                chip->playback_streams = ICH6_NUM_PLAYBACK;
                chip->capture_streams = ICH6_NUM_CAPTURE;
@@ -1621,6 +1636,7 @@ static struct pci_device_id azx_ids[] __devinitdata = {
        { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
        { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
        { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
+       { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
        { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
        { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
        { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
index acaef3c811b8c4791271f2250603d8cce6160e32..0b668793face2af3a04e48e26b0d3f95b1f2b143 100644 (file)
@@ -12,6 +12,8 @@ extern struct hda_codec_preset snd_hda_preset_analog[];
 extern struct hda_codec_preset snd_hda_preset_sigmatel[];
 /* SiLabs 3054/3055 modem codecs */
 extern struct hda_codec_preset snd_hda_preset_si3054[];
+/* ATI HDMI codecs */
+extern struct hda_codec_preset snd_hda_preset_atihdmi[];
 
 static const struct hda_codec_preset *hda_preset_tables[] = {
        snd_hda_preset_realtek,
@@ -19,5 +21,6 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
        snd_hda_preset_analog,
        snd_hda_preset_sigmatel,
        snd_hda_preset_si3054,
+       snd_hda_preset_atihdmi,
        NULL
 };
index ca514a6a58751781e809c10a010eaf74ef8fea26..c2f0fe85bf35c901966899f5d9c78274667027ad 100644 (file)
@@ -182,6 +182,10 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
                snd_iprintf(buffer, " OUT");
        if (caps & AC_PINCAP_HP_DRV)
                snd_iprintf(buffer, " HP");
+       if (caps & AC_PINCAP_EAPD)
+               snd_iprintf(buffer, " EAPD");
+       if (caps & AC_PINCAP_PRES_DETECT)
+               snd_iprintf(buffer, " Detect");
        snd_iprintf(buffer, "\n");
        caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
        snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
@@ -318,7 +322,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info);
+       snd_info_set_text_ops(entry, codec, print_codec_info);
        return 0;
 }
 
index 40f000ba136269776ae1583ad0e9cea1555ce54a..dd4e00a82b55fdd79eb7f7a08182f193f85dd724 100644 (file)
@@ -789,6 +789,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
        { .modelname = "3stack",        .config = AD1986A_3STACK },
        { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84,
          .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
+       { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3,
+         .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */
        { .modelname = "laptop",        .config = AD1986A_LAPTOP },
        { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
          .config = AD1986A_LAPTOP }, /* FSC V2060 */
@@ -809,6 +811,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = {
          .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */
        { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af,
          .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */
+       { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066,
+         .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */
        {}
 };
 
@@ -963,7 +967,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
                .info = ad1983_spdif_route_info,
                .get = ad1983_spdif_route_get,
                .put = ad1983_spdif_route_put,
@@ -1103,7 +1107,7 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
        /* identical with AD1983 */
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
                .info = ad1983_spdif_route_info,
                .get = ad1983_spdif_route_get,
                .put = ad1983_spdif_route_put,
@@ -1329,13 +1333,60 @@ static int ad1981_hp_init(struct hda_codec *codec)
        return 0;
 }
 
+/* configuration for Lenovo Thinkpad T60 */
+static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Capture Source",
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       /* identical with AD1983 */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+               .info = ad1983_spdif_route_info,
+               .get = ad1983_spdif_route_get,
+               .put = ad1983_spdif_route_put,
+       },
+       { } /* end */
+};
+
+static struct hda_input_mux ad1981_thinkpad_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Mix", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
 /* models */
-enum { AD1981_BASIC, AD1981_HP };
+enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD };
 
 static struct hda_board_config ad1981_cfg_tbl[] = {
        { .modelname = "hp", .config = AD1981_HP },
        /* All HP models */
        { .pci_subvendor = 0x103c, .config = AD1981_HP },
+       { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c,
+         .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */
+       { .modelname = "thinkpad", .config = AD1981_THINKPAD },
+       /* Lenovo Thinkpad T60/X60/Z6xx */
+       { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD },
+       { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597,
+         .config = AD1981_THINKPAD }, /* Z60m/t */
        { .modelname = "basic", .config = AD1981_BASIC },
        {}
 };
@@ -1381,6 +1432,10 @@ static int patch_ad1981(struct hda_codec *codec)
                codec->patch_ops.init = ad1981_hp_init;
                codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
                break;
+       case AD1981_THINKPAD:
+               spec->mixers[0] = ad1981_thinkpad_mixers;
+               spec->input_mux = &ad1981_thinkpad_capture_source;
+               break;
        }
 
        return 0;
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
new file mode 100644 (file)
index 0000000..a27440f
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for ATI HDMI codecs
+ *
+ * Copyright (c) 2006 ATI Technologies Inc.
+ *
+ *
+ *  This driver 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 driver 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+struct atihdmi_spec {
+       struct hda_multi_out multiout;
+
+       struct hda_pcm pcm_rec;
+};
+
+static struct hda_verb atihdmi_basic_init[] = {
+       /* enable digital output on pin widget */
+       { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       {} /* terminator */
+};
+
+/*
+ * Controls
+ */
+static int atihdmi_build_controls(struct hda_codec *codec)
+{
+       struct atihdmi_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+       snd_hda_sequence_write(codec, atihdmi_basic_init);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * resume
+ */
+static int atihdmi_resume(struct hda_codec *codec)
+{
+       atihdmi_init(codec);
+       snd_hda_resume_spdif_out(codec);
+
+       return 0;
+}
+#endif
+
+/*
+ * Digital out
+ */
+static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    struct snd_pcm_substream *substream)
+{
+       struct atihdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     struct snd_pcm_substream *substream)
+{
+       struct atihdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x2, /* NID to query formats and rates and setup streams */
+       .ops = {
+               .open = atihdmi_dig_playback_pcm_open,
+               .close = atihdmi_dig_playback_pcm_close
+       },
+};
+
+static int atihdmi_build_pcms(struct hda_codec *codec)
+{
+       struct atihdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = &spec->pcm_rec;
+
+       codec->num_pcms = 1;
+       codec->pcm_info = info;
+
+       info->name = "ATI HDMI";
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
+
+       return 0;
+}
+
+static void atihdmi_free(struct hda_codec *codec)
+{
+       kfree(codec->spec);
+}
+
+static struct hda_codec_ops atihdmi_patch_ops = {
+       .build_controls = atihdmi_build_controls,
+       .build_pcms = atihdmi_build_pcms,
+       .init = atihdmi_init,
+       .free = atihdmi_free,
+#ifdef CONFIG_PM
+       .resume = atihdmi_resume,
+#endif
+};
+
+static int patch_atihdmi(struct hda_codec *codec)
+{
+       struct atihdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->multiout.num_dacs = 0;      /* no analog */
+       spec->multiout.max_channels = 2;
+       spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital,
+                                          * seems to be unused in pure-digital
+                                          * case. */
+
+       codec->patch_ops = atihdmi_patch_ops;
+
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_atihdmi[] = {
+       { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
+       {} /* terminator */
+};
index f0e9a9c907808838568110b8dc05f34832161dfd..98b9f16c26ffa633d016294e1c47f63f073d3408 100644 (file)
@@ -2174,6 +2174,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
 
        { .modelname = "lg", .config = ALC880_LG },
        { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
+       { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG },
 
        { .modelname = "lg-lw", .config = ALC880_LG_LW },
        { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW },
@@ -3105,6 +3106,7 @@ static struct hda_verb alc260_init_verbs[] = {
        { }
 };
 
+#if 0 /* should be identical with alc260_init_verbs? */
 static struct hda_verb alc260_hp_init_verbs[] = {
        /* Headphone and output */
        {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
@@ -3151,6 +3153,7 @@ static struct hda_verb alc260_hp_init_verbs[] = {
        {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
        { }
 };
+#endif
 
 static struct hda_verb alc260_hp_3013_init_verbs[] = {
        /* Line out and output */
@@ -3822,12 +3825,16 @@ static struct hda_board_config alc260_cfg_tbl[] = {
        { .modelname = "basic", .config = ALC260_BASIC },
        { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
          .config = ALC260_BASIC }, /* Sony VAIO */
+       { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc,
+         .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */
+       { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd,
+         .config = ALC260_BASIC }, /* Sony VAIO */
        { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
          .config = ALC260_BASIC }, /* CTL Travel Master U553W */
        { .modelname = "hp", .config = ALC260_HP },
        { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP },
        { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
-       { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP },
+       { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 },
        { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
        { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
        { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
@@ -3862,7 +3869,7 @@ static struct alc_config_preset alc260_presets[] = {
                .mixers = { alc260_base_output_mixer,
                            alc260_input_mixer,
                            alc260_capture_alt_mixer },
-               .init_verbs = { alc260_hp_init_verbs },
+               .init_verbs = { alc260_init_verbs },
                .num_dacs = ARRAY_SIZE(alc260_dac_nids),
                .dac_nids = alc260_dac_nids,
                .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
@@ -4094,21 +4101,6 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 3,
-               .info = alc882_mux_enum_info,
-               .get = alc882_mux_enum_get,
-               .put = alc882_mux_enum_put,
-       },
        { } /* end */
 };
 
@@ -4342,8 +4334,6 @@ static struct alc_config_preset alc882_presets[] = {
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
-               .adc_nids = alc882_adc_nids,
                .dig_in_nid = ALC882_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
                .channel_mode = alc882_ch_modes,
@@ -4355,8 +4345,6 @@ static struct alc_config_preset alc882_presets[] = {
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
                .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
-               .adc_nids = alc882_adc_nids,
                .dig_in_nid = ALC882_DIGIN_NID,
                .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
                .channel_mode = alc882_sixstack_modes,
index 8c440fb98603aab986aedc734ec716331b529999..36f199442fdc631307fb99630821f565728ea842 100644 (file)
@@ -41,6 +41,7 @@
 #define STAC_REF               0
 #define STAC_D945GTP3          1
 #define STAC_D945GTP5          2
+#define STAC_MACMINI           3
 
 struct sigmatel_spec {
        struct snd_kcontrol_new *mixers[4];
@@ -52,6 +53,7 @@ struct sigmatel_spec {
        unsigned int mic_switch: 1;
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
+       unsigned int gpio_mute: 1;
 
        /* playback */
        struct hda_multi_out multiout;
@@ -293,6 +295,7 @@ static unsigned int *stac922x_brd_tbl[] = {
        ref922x_pin_configs,
        d945gtp3_pin_configs,
        d945gtp5_pin_configs,
+       NULL,           /* STAC_MACMINI */
 };
 
 static struct hda_board_config stac922x_cfg_tbl[] = {
@@ -324,6 +327,9 @@ static struct hda_board_config stac922x_cfg_tbl[] = {
        { .pci_subvendor = PCI_VENDOR_ID_INTEL,
          .pci_subdevice = 0x0417,
          .config = STAC_D945GTP5 },    /* Intel D975XBK - 5 Stack */
+       { .pci_subvendor = 0x8384,
+         .pci_subdevice = 0x7680,
+         .config = STAC_MACMINI },     /* Apple Mac Mini (early 2006) */
        {} /* terminator */
 };
 
@@ -841,6 +847,19 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
                }
        }
 
+       if (imux->num_items == 1) {
+               /*
+                * Set the current input for the muxes.
+                * The STAC9221 has two input muxes with identical source
+                * NID lists.  Hopefully this won't get confused.
+                */
+               for (i = 0; i < spec->num_muxes; i++) {
+                       snd_hda_codec_write(codec, spec->mux_nids[i], 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           imux->items[0].index);
+               }
+       }
+
        return 0;
 }
 
@@ -946,6 +965,45 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
+/*
+ * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
+ * funky external mute control using GPIO pins.
+ */
+
+static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
+{
+       unsigned int gpiostate, gpiomask, gpiodir;
+
+       gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+                                      AC_VERB_GET_GPIO_DATA, 0);
+
+       if (!muted)
+               gpiostate |= (1 << pin);
+       else
+               gpiostate &= ~(1 << pin);
+
+       gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+                                     AC_VERB_GET_GPIO_MASK, 0);
+       gpiomask |= (1 << pin);
+
+       gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+                                    AC_VERB_GET_GPIO_DIRECTION, 0);
+       gpiodir |= (1 << pin);
+
+       /* AppleHDA seems to do this -- WTF is this verb?? */
+       snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
+
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_MASK, gpiomask);
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+
+       msleep(1);
+
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DATA, gpiostate);
+}
+
 static int stac92xx_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -982,6 +1040,11 @@ static int stac92xx_init(struct hda_codec *codec)
                stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
                                         AC_PINCTL_IN_EN);
 
+       if (spec->gpio_mute) {
+               stac922x_gpio_mute(codec, 0, 0);
+               stac922x_gpio_mute(codec, 1, 0);
+       }
+
        return 0;
 }
 
@@ -1132,7 +1195,7 @@ static int patch_stac922x(struct hda_codec *codec)
        spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl);
        if (spec->board_config < 0)
                 snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, using BIOS defaults\n");
-       else {
+       else if (stac922x_brd_tbl[spec->board_config] != NULL) {
                spec->num_pins = 10;
                spec->pin_nids = stac922x_pin_nids;
                spec->pin_configs = stac922x_brd_tbl[spec->board_config];
@@ -1154,6 +1217,9 @@ static int patch_stac922x(struct hda_codec *codec)
                return err;
        }
 
+       if (spec->board_config == STAC_MACMINI)
+               spec->gpio_mute = 1;
+
        codec->patch_ops = stac92xx_patch_ops;
 
        return 0;
@@ -1262,13 +1328,13 @@ static int vaio_master_sw_put(struct snd_kcontrol *kcontrol,
        int change;
 
        change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
-                                         0x80, valp[0] & 0x80);
+                                         0x80, (valp[0] ? 0 : 0x80));
        change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
-                                          0x80, valp[1] & 0x80);
+                                          0x80, (valp[1] ? 0 : 0x80));
        snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
-                                0x80, valp[0] & 0x80);
+                                0x80, (valp[0] ? 0 : 0x80));
        snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
-                                0x80, valp[1] & 0x80);
+                                0x80, (valp[1] ? 0 : 0x80));
        return change;
 }
 
@@ -1370,6 +1436,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x },
        { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x },
        { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x },
+       { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac922x },
+       { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac922x },
+       { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac922x },
+       { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac922x },
+       { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac922x },
+       { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac922x },
        { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x },
        { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x },
        { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x },
index 336dc489aee1f23ec648a7e816bc60c90674eb87..ca74f5b85f42070dd611967e5ae3b01034058a7f 100644 (file)
@@ -1281,9 +1281,15 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
 
        tmp2 = tmp = snd_ice1712_gpio_read(ice);
        if (enable)
-               tmp |= AUREON_HP_SEL;
+               if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+                       tmp |= AUREON_HP_SEL;
+               else
+                       tmp |= PRODIGY_HP_SEL;
        else
-               tmp &= ~ AUREON_HP_SEL;
+               if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT)
+                       tmp &= ~ AUREON_HP_SEL;
+               else
+                       tmp &= ~ PRODIGY_HP_SEL;
        if (tmp != tmp2) {
                snd_ice1712_gpio_write(ice, tmp);
                return 1;
@@ -2079,16 +2085,16 @@ static unsigned char prodigy71_eeprom[] __devinitdata = {
 };
 
 static unsigned char prodigy71lt_eeprom[] __devinitdata = {
-       0x0b,   /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
+       0x4b,   /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
        0x80,   /* ACLINK: I2S */
        0xfc,   /* I2S: vol, 96k, 24bit, 192k */
-       0xc3,   /* SPDUF: out-en, out-int */
-       0x00,   /* GPIO_DIR */
-       0x07,   /* GPIO_DIR1 */
-       0x00,   /* GPIO_DIR2 */
-       0xff,   /* GPIO_MASK */
-       0xf8,   /* GPIO_MASK1 */
-       0xff,   /* GPIO_MASK2 */
+       0xc3,   /* SPDIF: out-en, out-int, spdif-in */
+       0xff,   /* GPIO_DIR */
+       0xff,   /* GPIO_DIR1 */
+       0x5f,   /* GPIO_DIR2 */
+       0x00,   /* GPIO_MASK */
+       0x00,   /* GPIO_MASK1 */
+       0x00,   /* GPIO_MASK2 */
        0x00,   /* GPIO_STATE */
        0x00,   /* GPIO_STATE1 */
        0x00,   /* GPIO_STATE2 */
index 98a6752280f26cf66fcc9d3cea0c376466cd9848..3b7bea656c57eec0a056dd02ec407b3f603c9a20 100644 (file)
@@ -58,5 +58,6 @@ extern struct snd_ice1712_card_info  snd_vt1724_aureon_cards[];
 #define PRODIGY_WM_CS          (1 << 8)
 #define PRODIGY_SPI_MOSI       (1 << 10)
 #define PRODIGY_SPI_CLK                (1 << 9)
+#define PRODIGY_HP_SEL         (1 << 5)
 
 #endif /* __SOUND_AUREON_H */
index 2c529e741384fbbf395348f228f3982339cf9f5a..b135389fec6c7cbc83e69a73f9f05f5cdf1272ef 100644 (file)
@@ -1031,6 +1031,9 @@ struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
                .model = "dmx6fire",
                .chip_init = snd_ice1712_ews_init,
                .build_controls = snd_ice1712_ews_add_controls,
+               .mpu401_1_name = "MIDI-Front DMX6fire",
+               .mpu401_2_name = "Wavetable DMX6fire",
+               .mpu401_2_info_flags = MPU401_INFO_OUTPUT,
        },
        { } /* terminator */
 };
index c56793b381e282a53218662d286b4ab20716bbb2..845907159b74cc8cbb230dd4f2f2eb736ed2f297 100644 (file)
@@ -61,7 +61,6 @@
 #include <sound/core.h>
 #include <sound/cs8427.h>
 #include <sound/info.h>
-#include <sound/mpu401.h>
 #include <sound/initval.h>
 
 #include <sound/asoundef.h>
@@ -1596,7 +1595,7 @@ static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(ice->card, "ice1712", &entry))
-               snd_info_set_text_ops(entry, ice, 1024, snd_ice1712_proc_read);
+               snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read);
 }
 
 /*
@@ -2398,13 +2397,14 @@ static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice)
        udelay(200);
        outb(ICE1712_NATIVE, ICEREG(ice, CONTROL));
        udelay(200);
-       if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && !ice->dxr_enable) {
-                /* Limit active ADCs and DACs to 6;  */
-                /* Note: DXR extension not supported */
-               pci_write_config_byte(ice->pci, 0x60, 0x2a);
-       } else {
-               pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
-       }
+       if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE &&
+           !ice->dxr_enable)
+               /*  Set eeprom value to limit active ADCs and DACs to 6;
+                *  Also disable AC97 as no hardware in standard 6fire card/box
+                *  Note: DXR extensions are not currently supported
+                */
+               ice->eeprom.data[ICE_EEP1_CODEC] = 0x3a;
+       pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
        pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]);
        pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]);
        pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]);
@@ -2737,21 +2737,38 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
 
        if (! c->no_mpu401) {
                if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
-                                              ICEREG(ice, MPU1_CTRL), 1,
+                                              ICEREG(ice, MPU1_CTRL),
+                                              (c->mpu401_1_info_flags |
+                                               MPU401_INFO_INTEGRATED),
                                               ice->irq, 0,
                                               &ice->rmidi[0])) < 0) {
                        snd_card_free(card);
                        return err;
                }
-
-               if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401)
+               if (c->mpu401_1_name)
+                       /*  Prefered name available in card_info */
+                       snprintf(ice->rmidi[0]->name,
+                                sizeof(ice->rmidi[0]->name),
+                                "%s %d", c->mpu401_1_name, card->number);
+
+               if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) {
+                       /*  2nd port used  */
                        if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
-                                                      ICEREG(ice, MPU2_CTRL), 1,
+                                                      ICEREG(ice, MPU2_CTRL),
+                                                      (c->mpu401_2_info_flags |
+                                                       MPU401_INFO_INTEGRATED),
                                                       ice->irq, 0,
                                                       &ice->rmidi[1])) < 0) {
                                snd_card_free(card);
                                return err;
                        }
+                       if (c->mpu401_2_name)
+                               /*  Prefered name available in card_info */
+                               snprintf(ice->rmidi[1]->name,
+                                        sizeof(ice->rmidi[1]->name),
+                                        "%s %d", c->mpu401_2_name,
+                                        card->number);
+               }
        }
 
        snd_ice1712_set_input_clock_source(ice, 0);
index 053f8e56fd685a15e7fddd47cdf3d1af9b9ab1dd..ce27eac40d4e15d5e8e10a5f3e94b65cda98d90b 100644 (file)
@@ -29,6 +29,7 @@
 #include <sound/ak4xxx-adda.h>
 #include <sound/ak4114.h>
 #include <sound/pcm.h>
+#include <sound/mpu401.h>
 
 
 /*
@@ -495,6 +496,10 @@ struct snd_ice1712_card_info {
        int (*chip_init)(struct snd_ice1712 *);
        int (*build_controls)(struct snd_ice1712 *);
        unsigned int no_mpu401: 1;
+       unsigned int mpu401_1_info_flags;
+       unsigned int mpu401_2_info_flags;
+       const char *mpu401_1_name;
+       const char *mpu401_2_name;
        unsigned int eeprom_size;
        unsigned char *eeprom_data;
 };
index b1c007e022d265bb33d8882f223e2bf34d2d5acf..34a58c629f47ebf715dcaddd3db5ce927dcfb94b 100644 (file)
@@ -1293,7 +1293,7 @@ static void __devinit snd_vt1724_proc_init(struct snd_ice1712 * ice)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(ice->card, "ice1724", &entry))
-               snd_info_set_text_ops(entry, ice, 1024, snd_vt1724_proc_read);
+               snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read);
 }
 
 /*
@@ -2388,7 +2388,8 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
        if (! c->no_mpu401) {
                if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
                        if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
-                                                      ICEREG1724(ice, MPU_CTRL), 1,
+                                                      ICEREG1724(ice, MPU_CTRL),
+                                                      MPU401_INFO_INTEGRATED,
                                                       ice->irq, 0,
                                                       &ice->rmidi[0])) < 0) {
                                snd_card_free(card);
index d23fb3fc21330fb4b8a25bd20f1b753ee4da2813..0efcad9260a5f99c0b10be7451509f1a8d8550f1 100644 (file)
@@ -680,9 +680,8 @@ static void wm_proc_init(struct snd_ice1712 *ice)
 {
        struct snd_info_entry *entry;
        if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) {
-               snd_info_set_text_ops(entry, ice, 1024, wm_proc_regs_read);
+               snd_info_set_text_ops(entry, ice, wm_proc_regs_read);
                entry->mode |= S_IWUSR;
-               entry->c.text.write_size = 1024;
                entry->c.text.write = wm_proc_regs_write;
        }
 }
@@ -705,9 +704,8 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff
 static void cs_proc_init(struct snd_ice1712 *ice)
 {
        struct snd_info_entry *entry;
-       if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) {
-               snd_info_set_text_ops(entry, ice, 1024, cs_proc_regs_read);
-       }
+       if (! snd_card_proc_new(ice->card, "cs_codec", &entry))
+               snd_info_set_text_ops(entry, ice, cs_proc_regs_read);
 }
 
 
index 0df7602568e2a8cb73054c1bb7730f0425300d34..edc14475ef827f32332e2ebe7fc89d3a7acbe0ff 100644 (file)
@@ -66,7 +66,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
-static int ac97_clock = 0;
+static int ac97_clock;
 static char *ac97_quirk;
 static int buggy_semaphore;
 static int buggy_irq = -1; /* auto-check */
@@ -1805,6 +1805,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "Dell Optiplex GX270",  /* AD1981B */
                .type = AC97_TUNE_HP_ONLY
        },
+       {
+               .subvendor = 0x1028,
+               .subdevice = 0x014e,
+               .name = "Dell D800", /* STAC9750/51 */
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x1028,
                .subdevice = 0x0163,
@@ -2645,7 +2651,7 @@ static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "intel8x0", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read);
 }
 #else
 #define snd_intel8x0_proc_init(x)
index 720635f0cb81a83e5c6d36d41d4f18dcf02ea278..24703d75b65a5ca9da6fafebb12f9510efe54675 100644 (file)
@@ -59,7 +59,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
 
 static int index = -2; /* Exclude the first card */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
-static int ac97_clock = 0;
+static int ac97_clock;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard.");
@@ -1092,7 +1092,7 @@ static void __devinit snd_intel8x0m_proc_init(struct intel8x0m * chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "intel8x0m", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0m_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_intel8x0m_proc_read);
 }
 #else /* !CONFIG_PROC_FS */
 #define snd_intel8x0m_proc_init(chip)
index e39fad1a420041cb5cb0aa3e1b3689dd473b128c..6e97932de34f337a23cd2dd1cd81839d8126c347 100644 (file)
@@ -2085,7 +2085,7 @@ static void __devinit snd_korg1212_proc_init(struct snd_korg1212 *korg1212)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(korg1212->card, "korg1212", &entry))
-               snd_info_set_text_ops(entry, korg1212, 1024, snd_korg1212_proc_read);
+               snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read);
 }
 
 static int
index 1928e06b6d82939fab3a687c1d3dea69f39da794..1c344fbd964de4a76f9c7915ba3970b87d299aab 100644 (file)
@@ -2861,7 +2861,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 #if 0 /* TODO: not supported yet */
        /* TODO enable MIDI IRQ and I/O */
        err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
-                                 chip->iobase + MPU401_DATA_PORT, 1,
+                                 chip->iobase + MPU401_DATA_PORT,
+                                 MPU401_INFO_INTEGRATED,
                                  chip->irq, 0, &chip->rmidi);
        if (err < 0)
                printk(KERN_WARNING "maestro3: no MIDI support.\n");
index 09cc0786495a00dd5456f3994affdaab5ecfa516..366c4a7e65c6a8f65f0d2a32af55ddfac88eb974 100644 (file)
@@ -1244,7 +1244,6 @@ static void __devinit snd_mixart_proc_init(struct snd_mixart *chip)
        /* text interface to read perf and temp meters */
        if (! snd_card_proc_new(chip->card, "board_info", &entry)) {
                entry->private_data = chip;
-               entry->c.text.read_size = 1024;
                entry->c.text.read = snd_mixart_proc_read;
        }
 
index dafa2235abaa1812a6360e1ad6cb59bd2aff0b52..8198884b51ee1fc7141eebad28ae7743f187485b 100644 (file)
@@ -1150,9 +1150,9 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "info", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_info);
+               snd_info_set_text_ops(entry, chip, pcxhr_proc_info);
        if (! snd_card_proc_new(chip->card, "sync", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_sync);
+               snd_info_set_text_ops(entry, chip, pcxhr_proc_sync);
 }
 /* end of proc interface */
 
index d8cc985d7241bfc20833d9c09fb1a9bc203dcdf4..5618ec9740bded1738a034868720d24db46ab239 100644 (file)
@@ -1836,11 +1836,11 @@ static int snd_riptide_free(struct snd_riptide *chip)
                UNSET_GRESET(cif->hwport);
                kfree(chip->cif);
        }
+       if (chip->irq >= 0)
+               free_irq(chip->irq, chip);
        if (chip->fw_entry)
                release_firmware(chip->fw_entry);
        release_and_free_resource(chip->res_port);
-       if (chip->irq >= 0)
-               free_irq(chip->irq, chip);
        kfree(chip);
        return 0;
 }
@@ -1992,7 +1992,7 @@ static void __devinit snd_riptide_proc_init(struct snd_riptide *chip)
        struct snd_info_entry *entry;
 
        if (!snd_card_proc_new(chip->card, "riptide", &entry))
-               snd_info_set_text_ops(entry, chip, 4096, snd_riptide_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_riptide_proc_read);
 }
 
 static int __devinit snd_riptide_mixer(struct snd_riptide *chip)
index 55b1d4838d9764c3dda6c1b91bb606eddbea78b9..2cb9fe98db2f51f43ba2bbe1ba51c929f9d1c667 100644 (file)
@@ -1368,18 +1368,18 @@ static int __devinit snd_rme32_create(struct rme32 * rme32)
                return err;
        rme32->port = pci_resource_start(rme32->pci, 0);
 
-       if (request_irq(pci->irq, snd_rme32_interrupt, SA_INTERRUPT | SA_SHIRQ, "RME32", (void *) rme32)) {
-               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
-               return -EBUSY;
-       }
-       rme32->irq = pci->irq;
-
        if ((rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE)) == 0) {
                snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n",
                           rme32->port, rme32->port + RME32_IO_SIZE - 1);
                return -ENOMEM;
        }
 
+       if (request_irq(pci->irq, snd_rme32_interrupt, SA_INTERRUPT | SA_SHIRQ, "RME32", (void *) rme32)) {
+               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               return -EBUSY;
+       }
+       rme32->irq = pci->irq;
+
        /* read the card's revision number */
        pci_read_config_byte(pci, 8, &rme32->rev);
 
@@ -1578,7 +1578,7 @@ static void __devinit snd_rme32_proc_init(struct rme32 * rme32)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(rme32->card, "rme32", &entry))
-               snd_info_set_text_ops(entry, rme32, 1024, snd_rme32_proc_read);
+               snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read);
 }
 
 /*
index 3c1bc533d511975b7d3dc71d95d9e24ee8bd743f..991cb18c14f3d14ce19ced4d319bdf89b38c96e1 100644 (file)
@@ -1151,6 +1151,25 @@ static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = {
        .mask = 0
 };
 
+static void
+rme96_set_buffer_size_constraint(struct rme96 *rme96,
+                                struct snd_pcm_runtime *runtime)
+{
+       unsigned int size;
+
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                    RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
+       if ((size = rme96->playback_periodsize) != 0 ||
+           (size = rme96->capture_periodsize) != 0)
+               snd_pcm_hw_constraint_minmax(runtime,
+                                            SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                            size, size);
+       else
+               snd_pcm_hw_constraint_list(runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                          &hw_constraints_period_bytes);
+}
+
 static int
 snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
 {
@@ -1180,8 +1199,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
                 runtime->hw.rate_min = rate;
                 runtime->hw.rate_max = rate;
        }        
-       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+       rme96_set_buffer_size_constraint(rme96, runtime);
 
        rme96->wcreg_spdif_stream = rme96->wcreg_spdif;
        rme96->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
@@ -1219,9 +1237,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
        rme96->capture_substream = substream;
        spin_unlock_irq(&rme96->lock);
        
-       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
-
+       rme96_set_buffer_size_constraint(rme96, runtime);
        return 0;
 }
 
@@ -1254,8 +1270,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
                 runtime->hw.rate_min = rate;
                 runtime->hw.rate_max = rate;
        }        
-       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+       rme96_set_buffer_size_constraint(rme96, runtime);
        return 0;
 }
 
@@ -1291,8 +1306,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
        rme96->capture_substream = substream;
        spin_unlock_irq(&rme96->lock);
 
-       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
+       rme96_set_buffer_size_constraint(rme96, runtime);
        return 0;
 }
 
@@ -1569,17 +1583,17 @@ snd_rme96_create(struct rme96 *rme96)
                return err;
        rme96->port = pci_resource_start(rme96->pci, 0);
 
+       if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) {
+               snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
+               return -ENOMEM;
+       }
+
        if (request_irq(pci->irq, snd_rme96_interrupt, SA_INTERRUPT|SA_SHIRQ, "RME96", (void *)rme96)) {
                snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
                return -EBUSY;
        }
        rme96->irq = pci->irq;
 
-       if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) {
-               snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1);
-               return -ENOMEM;
-       }
-
        /* read the card's revision number */
        pci_read_config_byte(pci, 8, &rme96->rev);      
        
@@ -1805,7 +1819,7 @@ snd_rme96_proc_init(struct rme96 *rme96)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(rme96->card, "rme96", &entry))
-               snd_info_set_text_ops(entry, rme96, 1024, snd_rme96_proc_read);
+               snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read);
 }
 
 /*
index 61f82f0d5cc67b1f7ad09d8cffd618c1b6c8dcb4..eaf3c22449ad62e2ff02f2c0650694b8ce2942e8 100644 (file)
@@ -389,7 +389,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
 
 /* use hotplug firmeare loader? */
 #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-#ifndef HDSP_USE_HWDEP_LOADER
+#if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP)
 #define HDSP_FW_LOADER
 #endif
 #endif
@@ -3169,9 +3169,10 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
        char *clock_source;
        int x;
 
-       if (hdsp_check_for_iobox (hdsp))
+       if (hdsp_check_for_iobox (hdsp)) {
                snd_iprintf(buffer, "No I/O box connected.\nPlease connect one and upload firmware.\n");
                return;
+        }
 
        if (hdsp_check_for_firmware(hdsp, 0)) {
                if (hdsp->state & HDSP_FirmwareCached) {
@@ -3470,7 +3471,7 @@ static void __devinit snd_hdsp_proc_init(struct hdsp *hdsp)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(hdsp->card, "hdsp", &entry))
-               snd_info_set_text_ops(entry, hdsp, 1024, snd_hdsp_proc_read);
+               snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read);
 }
 
 static void snd_hdsp_free_buffers(struct hdsp *hdsp)
index 722b9e6ce54a0694ba502d1bdde8e79cb2d1c3b5..bba1615504d3d78d7fe11dcd05e511d62d1536ea 100644 (file)
@@ -2489,7 +2489,7 @@ static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm)
        struct snd_info_entry *entry;
 
        if (!snd_card_proc_new(hdspm->card, "hdspm", &entry))
-               snd_info_set_text_ops(entry, hdspm, 1024,
+               snd_info_set_text_ops(entry, hdspm,
                                      snd_hdspm_proc_read);
 }
 
index 75d6406303d36daaa58c4f6e1b0c0d5d217db58c..3b945e8c1b154ee5b474a7ca0dfb3c2189d1dbf9 100644 (file)
@@ -41,7 +41,7 @@
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int precise_ptr[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Enable precise pointer */
+static int precise_ptr[SNDRV_CARDS];                   /* Enable precise pointer */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard.");
@@ -1787,7 +1787,7 @@ static void __devinit snd_rme9652_proc_init(struct snd_rme9652 *rme9652)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(rme9652->card, "rme9652", &entry))
-               snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read);
+               snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read);
 }
 
 static void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652)
index 91f8bf3ae9fac562d3a48b3730e30ff70ee6ac3a..dcf4029483474bd3790b6ef45e7e71d434491d8b 100644 (file)
@@ -54,8 +54,8 @@ MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int reverb[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int mge[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int reverb[SNDRV_CARDS];
+static int mge[SNDRV_CARDS];
 static unsigned int dmaio = 0x7a00;    /* DDMA i/o address */
 
 module_param_array(index, int, NULL, 0444);
@@ -1144,7 +1144,7 @@ static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry))
-               snd_info_set_text_ops(entry, sonic, 1024, snd_sonicvibes_proc_read);
+               snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read);
 }
 
 /*
@@ -1456,7 +1456,7 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
                return err;
        }
        if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES,
-                                      sonic->midi_port, 1,
+                                      sonic->midi_port, MPU401_INFO_INTEGRATED,
                                       sonic->irq, 0,
                                       &midi_uart)) < 0) {
                snd_card_free(card);
index 9624a5f2b87599044201784a48fc87bd1ee22656..5629b7eba96d3845f2aa05a9ff7bc22db78d4fa9 100644 (file)
@@ -148,7 +148,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
        }
        if (trident->device != TRIDENT_DEVICE_ID_SI7018 &&
            (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE,
-                                      trident->midi_port, 1,
+                                      trident->midi_port,
+                                      MPU401_INFO_INTEGRATED,
                                       trident->irq, 0, &trident->rmidi)) < 0) {
                snd_card_free(card);
                return err;
index 52178b8ad49d93af8d172925106721b0b658c36b..d99ed7237750eb08e5c8706e09a6017ab979ebb5 100644 (file)
@@ -306,6 +306,8 @@ void snd_trident_start_voice(struct snd_trident * trident, unsigned int voice)
        outl(mask, TRID_REG(trident, reg));
 }
 
+EXPORT_SYMBOL(snd_trident_start_voice);
+
 /*---------------------------------------------------------------------------
    void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice)
 
@@ -328,6 +330,8 @@ void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice)
        outl(mask, TRID_REG(trident, reg));
 }
 
+EXPORT_SYMBOL(snd_trident_stop_voice);
+
 /*---------------------------------------------------------------------------
     int snd_trident_allocate_pcm_channel(struct snd_trident *trident)
   
@@ -502,6 +506,8 @@ void snd_trident_write_voice_regs(struct snd_trident * trident,
 #endif
 }
 
+EXPORT_SYMBOL(snd_trident_write_voice_regs);
+
 /*---------------------------------------------------------------------------
    snd_trident_write_cso_reg
   
@@ -3332,7 +3338,7 @@ static void __devinit snd_trident_proc_init(struct snd_trident * trident)
        if (trident->device == TRIDENT_DEVICE_ID_SI7018)
                s = "sis7018";
        if (! snd_card_proc_new(trident->card, s, &entry))
-               snd_info_set_text_ops(entry, trident, 1024, snd_trident_proc_read);
+               snd_info_set_text_ops(entry, trident, snd_trident_proc_read);
 }
 
 static int snd_trident_dev_free(struct snd_device *device)
@@ -3884,6 +3890,8 @@ struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident,
        return NULL;
 }
 
+EXPORT_SYMBOL(snd_trident_alloc_voice);
+
 void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice)
 {
        unsigned long flags;
@@ -3912,6 +3920,8 @@ void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voi
                private_free(voice);
 }
 
+EXPORT_SYMBOL(snd_trident_free_voice);
+
 static void snd_trident_clear_voices(struct snd_trident * trident, unsigned short v_min, unsigned short v_max)
 {
        unsigned int i, val, mask[2] = { 0, 0 };
@@ -3993,13 +4003,3 @@ int snd_trident_resume(struct pci_dev *pci)
        return 0;
 }
 #endif /* CONFIG_PM */
-
-EXPORT_SYMBOL(snd_trident_alloc_voice);
-EXPORT_SYMBOL(snd_trident_free_voice);
-EXPORT_SYMBOL(snd_trident_start_voice);
-EXPORT_SYMBOL(snd_trident_stop_voice);
-EXPORT_SYMBOL(snd_trident_write_voice_regs);
-/* trident_memory.c symbols */
-EXPORT_SYMBOL(snd_trident_synth_alloc);
-EXPORT_SYMBOL(snd_trident_synth_free);
-EXPORT_SYMBOL(snd_trident_synth_copy_from_user);
index 46c6982c9e88b88162c76ae0de8ba76e089b5116..aff3f874131cdb89e141ffd63065d06a6eb4e63a 100644 (file)
@@ -349,6 +349,7 @@ snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size)
        return blk;
 }
 
+EXPORT_SYMBOL(snd_trident_synth_alloc);
 
 /*
  * free a synth sample area
@@ -365,6 +366,7 @@ snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_trident_synth_free);
 
 /*
  * reset TLB entry and free kernel page
@@ -486,3 +488,4 @@ int snd_trident_synth_copy_from_user(struct snd_trident *trident,
        return 0;
 }
 
+EXPORT_SYMBOL(snd_trident_synth_copy_from_user);
index cc7af8bc55a0a0f83f5e30b94534bd4581c67695..9b7dee84743bc16b367a71307677ead56d822ed8 100644 (file)
@@ -914,7 +914,9 @@ static int snd_trident_synth_create_port(struct snd_trident * trident, int idx)
                                                   &callbacks,
                                                   SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
                                                   SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
-                                                  SNDRV_SEQ_PORT_TYPE_SYNTH,
+                                                  SNDRV_SEQ_PORT_TYPE_SYNTH |
+                                                  SNDRV_SEQ_PORT_TYPE_HARDWARE |
+                                                  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
                                                   16, 0,
                                                   name);
        if (p->chset->port < 0) {
index 39daf62d2bad55a4ba376ce9c300bff7e2a838cd..2527bbd958c551f30fc83655ee83d06161bee6d0 100644 (file)
@@ -1775,6 +1775,12 @@ static struct ac97_quirk ac97_quirks[] = {
                .name = "Targa Traveller 811",
                .type = AC97_TUNE_HP_ONLY,
        },
+       {
+               .subvendor = 0x161f,
+               .subdevice = 0x2032,
+               .name = "m680x",
+               .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */
+       },
        { } /* terminator */
 };
 
@@ -1973,7 +1979,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
        pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg);
        if (chip->mpu_res) {
                if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A,
-                                       mpu_port, 1,
+                                       mpu_port, MPU401_INFO_INTEGRATED,
                                        chip->irq, 0, &chip->rmidi) < 0) {
                        printk(KERN_WARNING "unable to initialize MPU-401"
                               " at 0x%lx, skipping\n", mpu_port);
@@ -2015,7 +2021,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx *chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "via82xx", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read);
 }
 
 /*
@@ -2365,7 +2371,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision)
                { .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */
                { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
                { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
-               { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
+               { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */
                { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
                { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
                { .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */
index ef97e50cd6c2ff8b51449abeb8fe1499141d9cce..577a2b03759fbc6503ab15e324dd7e963708bbc5 100644 (file)
@@ -929,7 +929,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx_modem *chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "via82xx", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read);
 }
 
 /*
index 65ebf5f1933a4639b4f3b0cd870516e00ed3557c..26aa775b7b69d17cddc05bd852fa350d4256fd7d 100644 (file)
@@ -308,7 +308,8 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
        }
        if (chip->mpu_res) {
                if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI,
-                                              mpu_port[dev], 1,
+                                              mpu_port[dev],
+                                              MPU401_INFO_INTEGRATED,
                                               pci->irq, 0, &chip->rawmidi)) < 0) {
                        printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]);
                        legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
index 8ac5ab50b5c7694b152e4559dece4e4fa7f6e1ff..f894752523bbd049120bef9f2a230513575e4546 100644 (file)
@@ -1919,7 +1919,7 @@ static int __devinit snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfp
        struct snd_info_entry *entry;
        
        if (! snd_card_proc_new(card, "ymfpci", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, snd_ymfpci_proc_read);
+               snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read);
        return 0;
 }
 
index bd0d70ff301941f11a926eeac02756edf11662c6..1dfe29b863d3d19c4d7e0f35480f9e8455f3e0fe 100644 (file)
@@ -144,7 +144,7 @@ static void pdacf_proc_init(struct snd_pdacf *chip)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, pdacf_proc_read);
+               snd_info_set_text_ops(entry, chip, pdacf_proc_read);
 }
 
 struct snd_pdacf *snd_pdacf_create(struct snd_card *card)
index 7f82f619f9f4c992c1fa72ff2a22f7e4bd6bf907..1ee0918c3b9f4bc43641b1040e4cbfa3c07952b6 100644 (file)
@@ -202,7 +202,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
        c |= (int)vx_inb(chip, RXM) << 8;
        c |= vx_inb(chip, RXL);
 
-       snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%x\n", c, fw->size);
+       snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%Zx\n", c, fw->size);
 
        vx_outb(chip, ICR, ICR_HF0);
 
index 7e0cda2b6ef9af174e94e5732fc2e33c26636aca..cafe6640cc1a6abdca63a2e5c1fc2cd985bfd9ad 100644 (file)
@@ -261,7 +261,7 @@ static int vxpocket_config(struct pcmcia_device *link)
 
        link->dev_node = &vxp->node;
        kfree(parse);
-       return 9;
+       return 0;
 
 cs_failed:
        cs_error(link, last_fn, last_ret);
index d6ba9959097bf647c4b5ffe2adc701d604c06d96..4d95c652c8cacd7fdc7616d609cfbbf294784b4a 100644 (file)
@@ -3,7 +3,7 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o toonie.o keywest.o beep.o
+snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
index f0794ef9d1ac06ffc404fcb353885a2e66593fea..b678814975c9e1dd93297033966a527172ec8b28 100644 (file)
@@ -867,8 +867,6 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
        unsigned int *prop, l;
        struct macio_chip* macio;
 
-       u32 layout_id = 0;
-
        if (!machine_is(powermac))
                return -ENODEV;
 
@@ -929,8 +927,14 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
        if (prop && *prop < 16)
                chip->subframe = *prop;
        prop = (unsigned int *) get_property(sound, "layout-id", NULL);
-       if (prop)
-               layout_id = *prop;
+       if (prop) {
+               /* partly deprecate snd-powermac, for those machines
+                * that have a layout-id property for now */
+               printk(KERN_INFO "snd-powermac no longer handles any "
+                                "machines with a layout-id property "
+                                "in the device-tree, use snd-aoa.\n");
+               return -ENODEV;
+       }
        /* This should be verified on older screamers */
        if (device_is_compatible(sound, "screamer")) {
                chip->model = PMAC_SCREAMER;
@@ -963,38 +967,6 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
                chip->freq_table = tumbler_freqs;
                chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
        }
-       if (device_is_compatible(sound, "AOAKeylargo") ||
-           device_is_compatible(sound, "AOAbase") ||
-           device_is_compatible(sound, "AOAK2")) {
-               /* For now, only support very basic TAS3004 based machines with
-                * single frequency until proper i2s control is implemented
-                */
-               switch(layout_id) {
-               case 0x24:
-               case 0x29:
-               case 0x33:
-               case 0x46:
-               case 0x48:
-               case 0x50:
-               case 0x5c:
-                       chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
-                       chip->model = PMAC_SNAPPER;
-                       chip->can_byte_swap = 0; /* FIXME: check this */
-                       chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
-                       break;
-               case 0x3a:
-                       chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
-                       chip->model = PMAC_TOONIE;
-                       chip->can_byte_swap = 0; /* FIXME: check this */
-                       chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */
-                       break;
-               default:
-                       printk(KERN_ERR "snd: Unknown layout ID 0x%x\n",
-                              layout_id);
-                       return -ENODEV;
-
-               }
-       }
        prop = (unsigned int *)get_property(sound, "device-id", NULL);
        if (prop)
                chip->device_id = *prop;
index 3a9bd4dbb9a6bfc5ec59a62d25d942f96240e35f..8394e66ceb004a50adec23c57a240b7980b8759e 100644 (file)
@@ -85,7 +85,7 @@ struct pmac_stream {
 
 enum snd_pmac_model {
        PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER,
-       PMAC_SNAPPER, PMAC_TOONIE
+       PMAC_SNAPPER
 };
 
 struct snd_pmac {
@@ -188,7 +188,6 @@ int snd_pmac_burgundy_init(struct snd_pmac *chip);
 int snd_pmac_daca_init(struct snd_pmac *chip);
 int snd_pmac_tumbler_init(struct snd_pmac *chip);
 int snd_pmac_tumbler_post_init(void);
-int snd_pmac_toonie_init(struct snd_pmac *chip);
 
 /* i2c functions */
 struct pmac_keywest {
index f4902a219e505176ce82e8f70dd28b2fff549dd5..fa9a44ab487e8a35a46e0a4086849943719c5f5f 100644 (file)
@@ -94,13 +94,6 @@ static int __init snd_pmac_probe(struct platform_device *devptr)
                if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0)
                        goto __error;
                break;
-       case PMAC_TOONIE:
-               strcpy(card->driver, "PMac Toonie");
-               strcpy(card->shortname, "PowerMac Toonie");
-               strcpy(card->longname, card->shortname);
-               if ((err = snd_pmac_toonie_init(chip)) < 0)
-                       goto __error;
-               break;
        case PMAC_AWACS:
        case PMAC_SCREAMER:
                name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS";
@@ -188,11 +181,15 @@ static int __init alsa_card_pmac_init(void)
        if ((err = platform_driver_register(&snd_pmac_driver)) < 0)
                return err;
        device = platform_device_register_simple(SND_PMAC_DRIVER, -1, NULL, 0);
-       if (IS_ERR(device)) {
-               platform_driver_unregister(&snd_pmac_driver);
-               return PTR_ERR(device);
-       }
-       return 0;
+       if (!IS_ERR(device)) {
+               if (platform_get_drvdata(device))
+                       return 0;
+               platform_device_unregister(device);
+               err = -ENODEV;
+       } else
+               err = PTR_ERR(device);
+       platform_driver_unregister(&snd_pmac_driver);
+       return err;
 
 }
 
index 1ac7c8552f50e3fdea0b07cb396906482681b554..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,378 +0,0 @@
-/*
- * Mac Mini "toonie" mixer control
- *
- * Copyright (c) 2005 by Benjamin Herrenschmidt <benh@kernel.crashing.org>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This 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 <sound/driver.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <sound/core.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include "pmac.h"
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-struct pmac_gpio {
-       unsigned int addr;
-       u8 active_val;
-       u8 inactive_val;
-       u8 active_state;
-};
-
-struct pmac_toonie
-{
-       struct pmac_gpio        hp_detect_gpio;
-       struct pmac_gpio        hp_mute_gpio;
-       struct pmac_gpio        amp_mute_gpio;
-       int                     hp_detect_irq;
-       int                     auto_mute_notify;
-       struct work_struct      detect_work;
-};
-
-
-/*
- * gpio access
- */
-#define do_gpio_write(gp, val) \
-       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, (gp)->addr, val)
-#define do_gpio_read(gp) \
-       pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, (gp)->addr, 0)
-#define tumbler_gpio_free(gp) /* NOP */
-
-static void write_audio_gpio(struct pmac_gpio *gp, int active)
-{
-       if (! gp->addr)
-               return;
-       active = active ? gp->active_val : gp->inactive_val;
-       do_gpio_write(gp, active);
-       DBG("(I) gpio %x write %d\n", gp->addr, active);
-}
-
-static int check_audio_gpio(struct pmac_gpio *gp)
-{
-       int ret;
-
-       if (! gp->addr)
-               return 0;
-
-       ret = do_gpio_read(gp);
-
-       return (ret & 0xd) == (gp->active_val & 0xd);
-}
-
-static int read_audio_gpio(struct pmac_gpio *gp)
-{
-       int ret;
-       if (! gp->addr)
-               return 0;
-       ret = ((do_gpio_read(gp) & 0x02) !=0);
-       return ret == gp->active_state;
-}
-
-
-enum { TOONIE_MUTE_HP, TOONIE_MUTE_AMP };
-
-static int toonie_get_mute_switch(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-       struct pmac_toonie *mix = chip->mixer_data;
-       struct pmac_gpio *gp;
-
-       if (mix == NULL)
-               return -ENODEV;
-       switch(kcontrol->private_value) {
-       case TOONIE_MUTE_HP:
-               gp = &mix->hp_mute_gpio;
-               break;
-       case TOONIE_MUTE_AMP:
-               gp = &mix->amp_mute_gpio;
-               break;
-       default:
-               return -EINVAL;
-       }
-       ucontrol->value.integer.value[0] = !check_audio_gpio(gp);
-       return 0;
-}
-
-static int toonie_put_mute_switch(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-       struct pmac_toonie *mix = chip->mixer_data;
-       struct pmac_gpio *gp;
-       int val;
-
-       if (chip->update_automute && chip->auto_mute)
-               return 0; /* don't touch in the auto-mute mode */
-
-       if (mix == NULL)
-               return -ENODEV;
-
-       switch(kcontrol->private_value) {
-       case TOONIE_MUTE_HP:
-               gp = &mix->hp_mute_gpio;
-               break;
-       case TOONIE_MUTE_AMP:
-               gp = &mix->amp_mute_gpio;
-               break;
-       default:
-               return -EINVAL;
-       }
-       val = ! check_audio_gpio(gp);
-       if (val != ucontrol->value.integer.value[0]) {
-               write_audio_gpio(gp, ! ucontrol->value.integer.value[0]);
-               return 1;
-       }
-       return 0;
-}
-
-static struct snd_kcontrol_new toonie_hp_sw __initdata = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Headphone Playback Switch",
-       .info = snd_pmac_boolean_mono_info,
-       .get = toonie_get_mute_switch,
-       .put = toonie_put_mute_switch,
-       .private_value = TOONIE_MUTE_HP,
-};
-static struct snd_kcontrol_new toonie_speaker_sw __initdata = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "PC Speaker Playback Switch",
-       .info = snd_pmac_boolean_mono_info,
-       .get = toonie_get_mute_switch,
-       .put = toonie_put_mute_switch,
-       .private_value = TOONIE_MUTE_AMP,
-};
-
-/*
- * auto-mute stuffs
- */
-static int toonie_detect_headphone(struct snd_pmac *chip)
-{
-       struct pmac_toonie *mix = chip->mixer_data;
-       int detect = 0;
-
-       if (mix->hp_detect_gpio.addr)
-               detect |= read_audio_gpio(&mix->hp_detect_gpio);
-       return detect;
-}
-
-static void toonie_check_mute(struct snd_pmac *chip, struct pmac_gpio *gp, int val,
-                             int do_notify, struct snd_kcontrol *sw)
-{
-       if (check_audio_gpio(gp) != val) {
-               write_audio_gpio(gp, val);
-               if (do_notify)
-                       snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                                      &sw->id);
-       }
-}
-
-static void toonie_detect_handler(void *self)
-{
-       struct snd_pmac *chip = (struct snd_pmac *) self;
-       struct pmac_toonie *mix;
-       int headphone;
-
-       if (!chip)
-               return;
-
-       mix = chip->mixer_data;
-       snd_assert(mix, return);
-
-       headphone = toonie_detect_headphone(chip);
-
-       DBG("headphone: %d, lineout: %d\n", headphone, lineout);
-
-       if (headphone) {
-               /* unmute headphone/lineout & mute speaker */
-               toonie_check_mute(chip, &mix->hp_mute_gpio, 0,
-                                 mix->auto_mute_notify, chip->master_sw_ctl);
-               toonie_check_mute(chip, &mix->amp_mute_gpio, 1,
-                                 mix->auto_mute_notify, chip->speaker_sw_ctl);
-       } else {
-               /* unmute speaker, mute others */
-               toonie_check_mute(chip, &mix->amp_mute_gpio, 0,
-                                 mix->auto_mute_notify, chip->speaker_sw_ctl);
-               toonie_check_mute(chip, &mix->hp_mute_gpio, 1,
-                                 mix->auto_mute_notify, chip->master_sw_ctl);
-       }
-       if (mix->auto_mute_notify) {
-               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                                      &chip->hp_detect_ctl->id);
-       }
-}
-
-static void toonie_update_automute(struct snd_pmac *chip, int do_notify)
-{
-       if (chip->auto_mute) {
-               struct pmac_toonie *mix;
-               mix = chip->mixer_data;
-               snd_assert(mix, return);
-               mix->auto_mute_notify = do_notify;
-               schedule_work(&mix->detect_work);
-       }
-}
-
-/* interrupt - headphone plug changed */
-static irqreturn_t toonie_hp_intr(int irq, void *devid, struct pt_regs *regs)
-{
-       struct snd_pmac *chip = devid;
-
-       if (chip->update_automute && chip->initialized) {
-               chip->update_automute(chip, 1);
-               return IRQ_HANDLED;
-       }
-       return IRQ_NONE;
-}
-
-/* look for audio gpio device */
-static int find_audio_gpio(const char *name, const char *platform,
-                          struct pmac_gpio *gp)
-{
-       struct device_node *np;
-       u32 *base, addr;
-
-       if (! (np = find_devices("gpio")))
-               return -ENODEV;
-
-       for (np = np->child; np; np = np->sibling) {
-               char *property = get_property(np, "audio-gpio", NULL);
-               if (property && strcmp(property, name) == 0)
-                       break;
-               if (device_is_compatible(np, name))
-                       break;
-       }
-       if (np == NULL)
-               return -ENODEV;
-
-       base = (u32 *)get_property(np, "AAPL,address", NULL);
-       if (! base) {
-               base = (u32 *)get_property(np, "reg", NULL);
-               if (!base) {
-                       DBG("(E) cannot find address for device %s !\n", name);
-                       return -ENODEV;
-               }
-               addr = *base;
-               if (addr < 0x50)
-                       addr += 0x50;
-       } else
-               addr = *base;
-
-       gp->addr = addr & 0x0000ffff;
-
-       /* Try to find the active state, default to 0 ! */
-       base = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
-       if (base) {
-               gp->active_state = *base;
-               gp->active_val = (*base) ? 0x5 : 0x4;
-               gp->inactive_val = (*base) ? 0x4 : 0x5;
-       } else {
-               u32 *prop = NULL;
-               gp->active_state = 0;
-               gp->active_val = 0x4;
-               gp->inactive_val = 0x5;
-               /* Here are some crude hacks to extract the GPIO polarity and
-                * open collector informations out of the do-platform script
-                * as we don't yet have an interpreter for these things
-                */
-               if (platform)
-                       prop = (u32 *)get_property(np, platform, NULL);
-               if (prop) {
-                       if (prop[3] == 0x9 && prop[4] == 0x9) {
-                               gp->active_val = 0xd;
-                               gp->inactive_val = 0xc;
-                       }
-                       if (prop[3] == 0x1 && prop[4] == 0x1) {
-                               gp->active_val = 0x5;
-                               gp->inactive_val = 0x4;
-                       }
-               }
-       }
-
-       DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n",
-           name, gp->addr, gp->active_state);
-
-       return (np->n_intrs > 0) ? np->intrs[0].line : 0;
-}
-
-static void toonie_cleanup(struct snd_pmac *chip)
-{
-       struct pmac_toonie *mix = chip->mixer_data;
-       if (! mix)
-               return;
-       if (mix->hp_detect_irq >= 0)
-               free_irq(mix->hp_detect_irq, chip);
-       kfree(mix);
-       chip->mixer_data = NULL;
-}
-
-int __init snd_pmac_toonie_init(struct snd_pmac *chip)
-{
-       struct pmac_toonie *mix;
-
-       mix = kmalloc(sizeof(*mix), GFP_KERNEL);
-       if (! mix)
-               return -ENOMEM;
-
-       chip->mixer_data = mix;
-       chip->mixer_free = toonie_cleanup;
-
-       find_audio_gpio("headphone-mute", NULL, &mix->hp_mute_gpio);
-       find_audio_gpio("amp-mute", NULL, &mix->amp_mute_gpio);
-       mix->hp_detect_irq = find_audio_gpio("headphone-detect",
-                                            NULL, &mix->hp_detect_gpio);
-
-       strcpy(chip->card->mixername, "PowerMac Toonie");
-
-       chip->master_sw_ctl = snd_ctl_new1(&toonie_hp_sw, chip);
-       snd_ctl_add(chip->card, chip->master_sw_ctl);
-
-       chip->speaker_sw_ctl = snd_ctl_new1(&toonie_speaker_sw, chip);
-       snd_ctl_add(chip->card, chip->speaker_sw_ctl);
-
-       INIT_WORK(&mix->detect_work, toonie_detect_handler, (void *)chip);
-
-       if (mix->hp_detect_irq >= 0) {
-               snd_pmac_add_automute(chip);
-
-               chip->detect_headphone = toonie_detect_headphone;
-               chip->update_automute = toonie_update_automute;
-               toonie_update_automute(chip, 0);
-
-               if (request_irq(mix->hp_detect_irq, toonie_hp_intr, 0,
-                               "Sound Headphone Detection", chip) < 0)
-                       mix->hp_detect_irq = -1;
-       }
-
-       return 0;
-}
-
index e622d08215c97e65bda17aa3642bb306071c7b51..5eecdd09a79ddd91a3345eb92f7a82303d474a3e 100644 (file)
@@ -92,7 +92,7 @@ MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
 #define D_USR  (1<<4)
 #define D_DESC (1<<5)
 
-static int dbri_debug = 0;
+static int dbri_debug;
 module_param(dbri_debug, int, 0644);
 MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");
 
@@ -593,7 +593,7 @@ struct snd_dbri {
 /* Return a pointer to dbri_streaminfo */
 #define DBRI_STREAM(dbri, substream)   &dbri->stream_info[DBRI_STREAMNO(substream)]
 
-static struct snd_dbri *dbri_list = NULL;      /* All DBRI devices */
+static struct snd_dbri *dbri_list;     /* All DBRI devices */
 
 /*
  * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
@@ -2521,11 +2521,11 @@ void snd_dbri_proc(struct snd_dbri * dbri)
        struct snd_info_entry *entry;
 
        if (! snd_card_proc_new(dbri->card, "regs", &entry))
-               snd_info_set_text_ops(entry, dbri, 1024, dbri_regs_read);
+               snd_info_set_text_ops(entry, dbri, dbri_regs_read);
 
 #ifdef DBRI_DEBUG
        if (! snd_card_proc_new(dbri->card, "debug", &entry)) {
-               snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read);
+               snd_info_set_text_ops(entry, dbri, dbri_debug_read);
                entry->mode = S_IFREG | S_IRUGO;        /* Readable only. */
        }
 #endif
index fc733bbf4487319588c96e2678cde9292651cc2d..573e3701c14f02f526bac8777d86fa922e36d2a0 100644 (file)
@@ -63,6 +63,7 @@ int snd_emux_new(struct snd_emux **remu)
        return 0;
 }
 
+EXPORT_SYMBOL(snd_emux_new);
 
 /*
  */
@@ -136,6 +137,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch
        return 0;
 }
 
+EXPORT_SYMBOL(snd_emux_register);
 
 /*
  */
@@ -171,18 +173,8 @@ int snd_emux_free(struct snd_emux *emu)
        return 0;
 }
 
-
-EXPORT_SYMBOL(snd_emux_new);
-EXPORT_SYMBOL(snd_emux_register);
 EXPORT_SYMBOL(snd_emux_free);
 
-EXPORT_SYMBOL(snd_emux_terminate_all);
-EXPORT_SYMBOL(snd_emux_lock_voice);
-EXPORT_SYMBOL(snd_emux_unlock_voice);
-
-/* soundfont.c */
-EXPORT_SYMBOL(snd_sf_linear_to_log);
-
 
 /*
  *  INIT part
index 1ba68ce302793c411867a3d8a7bc0b26f837b7d0..58b9601f3ad0cf3428cdbf307ddc93cb9c34768a 100644 (file)
@@ -119,7 +119,6 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device)
 
        entry->content = SNDRV_INFO_CONTENT_TEXT;
        entry->private_data = emu;
-       entry->c.text.read_size = 1024;
        entry->c.text.read = snd_emux_proc_info_read;
        if (snd_info_register(entry) < 0)
                snd_info_free_entry(entry);
index 8f00f07701c460437d848996dea949e89cb254e8..d176cc01742d2069a400bfaf5585bfed1fb2e052 100644 (file)
@@ -55,7 +55,8 @@ static struct snd_midi_op emux_ops = {
                                 SNDRV_SEQ_PORT_TYPE_MIDI_GM |\
                                 SNDRV_SEQ_PORT_TYPE_MIDI_GS |\
                                 SNDRV_SEQ_PORT_TYPE_MIDI_XG |\
-                                SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE)
+                                SNDRV_SEQ_PORT_TYPE_HARDWARE |\
+                                SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
 
 /*
  * Initialise the EMUX Synth by creating a client and registering
index 24705d15ebd80e89b58e9c7c66885e2729490f2c..3733118d39bb03a59dcf1ca40019c80dafb889ef 100644 (file)
@@ -434,6 +434,7 @@ snd_emux_terminate_all(struct snd_emux *emu)
        spin_unlock_irqrestore(&emu->voice_lock, flags);
 }
 
+EXPORT_SYMBOL(snd_emux_terminate_all);
 
 /*
  * Terminate all voices associated with the given port
@@ -951,6 +952,8 @@ void snd_emux_lock_voice(struct snd_emux *emu, int voice)
        spin_unlock_irqrestore(&emu->voice_lock, flags);
 }
 
+EXPORT_SYMBOL(snd_emux_lock_voice);
+
 /*
  */
 void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
@@ -965,3 +968,5 @@ void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
                           voice, emu->voices[voice].state);
        spin_unlock_irqrestore(&emu->voice_lock, flags);
 }
+
+EXPORT_SYMBOL(snd_emux_unlock_voice);
index 32c27162dfb60ade704ca6f9a75288f33062dce4..455e535933ecf0b3ac1a182588677a3ae31b95eb 100644 (file)
@@ -195,7 +195,7 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
                break;
        case SNDRV_SFNT_REMOVE_INFO:
                /* patch must be opened */
-               if (sflist->currsf) {
+               if (!sflist->currsf) {
                        snd_printk("soundfont: remove_info: patch not opened\n");
                        rc = -EINVAL;
                } else {
@@ -810,6 +810,9 @@ snd_sf_linear_to_log(unsigned int amount, int offset, int ratio)
        return v;
 }
 
+EXPORT_SYMBOL(snd_sf_linear_to_log);
+
+
 #define OFFSET_MSEC            653117          /* base = 1000 */
 #define OFFSET_ABSCENT         851781          /* base = 8176 */
 #define OFFSET_SAMPLERATE      1011119         /* base = 44100 */
@@ -1485,4 +1488,3 @@ snd_soundfont_remove_unlocked(struct snd_sf_list *sflist)
        unlock_preset(sflist);
        return 0;
 }
-
index 4e614ac39f2194e22c227ca7854377a6964bed18..627de9525a32594b2ce2fcb84325b43189cbc0a6 100644 (file)
@@ -2138,7 +2138,7 @@ static void proc_pcm_format_add(struct snd_usb_stream *stream)
 
        sprintf(name, "stream%d", stream->pcm_index);
        if (! snd_card_proc_new(card, name, &entry))
-               snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read);
+               snd_info_set_text_ops(entry, stream, proc_pcm_format_read);
 }
 
 #else
@@ -2627,9 +2627,10 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                if (!csep && altsd->bNumEndpoints >= 2)
                        csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
                if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-                       snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n",
+                       snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
+                                  " class specific endpoint descriptor\n",
                                   dev->devnum, iface_no, altno);
-                       continue;
+                       csep = NULL;
                }
 
                fp = kmalloc(sizeof(*fp), GFP_KERNEL);
@@ -2648,7 +2649,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
                        fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
                                        * (fp->maxpacksize & 0x7ff);
-               fp->attributes = csep[3];
+               fp->attributes = csep ? csep[3] : 0;
 
                /* some quirks for attributes here */
 
@@ -2980,7 +2981,7 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
                return -ENXIO;
        alts = &iface->altsetting[1];
        altsd = get_iface_desc(alts);
-       if (alts->extralen != 11 || alts->extra[1] != CS_AUDIO_INTERFACE ||
+       if (alts->extralen != 11 || alts->extra[1] != USB_DT_CS_INTERFACE ||
            altsd->bNumEndpoints != 1)
                return -ENXIO;
 
@@ -3197,9 +3198,9 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
 {
        struct snd_info_entry *entry;
        if (! snd_card_proc_new(chip->card, "usbbus", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read);
+               snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read);
        if (! snd_card_proc_new(chip->card, "usbid", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read);
+               snd_info_set_text_ops(entry, chip, proc_audio_usbid_read);
 }
 
 /*
index 88733524d0fb1c78fde79bd6e6d0e10f5affd300..0f4b2b8541d6a54e1d2deeb6bf6e49324bba9933 100644 (file)
 #define USB_SUBCLASS_MIDI_STREAMING    0x03
 #define USB_SUBCLASS_VENDOR_SPEC       0xff
 
-#define CS_AUDIO_UNDEFINED             0x20
-#define CS_AUDIO_DEVICE                        0x21
-#define CS_AUDIO_CONFIGURATION         0x22
-#define CS_AUDIO_STRING                        0x23
-#define CS_AUDIO_INTERFACE             0x24
-#define CS_AUDIO_ENDPOINT              0x25
-
 #define HEADER                         0x01
 #define INPUT_TERMINAL                 0x02
 #define OUTPUT_TERMINAL                        0x03
index 2b9d940c8064e705cf7bfd27dd674f2e4780dc71..5105b6b057484ffb0408e509e90f70a45e3d799e 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/usb.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
+#include <sound/asequencer.h>
 #include "usbaudio.h"
 
 
@@ -1010,97 +1011,157 @@ static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_m
  * "(product) MIDI (n)" schema because they aren't external MIDI ports,
  * such as internal control or synthesizer ports.
  */
-static struct {
+static struct port_info {
        u32 id;
-       int port;
-       const char *name_format;
-} snd_usbmidi_port_names[] = {
+       short int port;
+       short int voices;
+       const char *name;
+       unsigned int seq_flags;
+} snd_usbmidi_port_info[] = {
+#define PORT_INFO(vendor, product, num, name_, voices_, flags) \
+       { .id = USB_ID(vendor, product), \
+         .port = num, .voices = voices_, \
+         .name = name_, .seq_flags = flags }
+#define EXTERNAL_PORT(vendor, product, num, name) \
+       PORT_INFO(vendor, product, num, name, 0, \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+                 SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+                 SNDRV_SEQ_PORT_TYPE_PORT)
+#define CONTROL_PORT(vendor, product, num, name) \
+       PORT_INFO(vendor, product, num, name, 0, \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+                 SNDRV_SEQ_PORT_TYPE_HARDWARE)
+#define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \
+       PORT_INFO(vendor, product, num, name, voices, \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GM | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GS | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_XG | \
+                 SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+                 SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
+#define SOUNDCANVAS_PORT(vendor, product, num, name, voices) \
+       PORT_INFO(vendor, product, num, name, voices, \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GM | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_GS | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_XG | \
+                 SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \
+                 SNDRV_SEQ_PORT_TYPE_HARDWARE | \
+                 SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)
        /* Roland UA-100 */
-       { USB_ID(0x0582, 0x0000), 2, "%s Control" },
+       CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"),
        /* Roland SC-8850 */
-       { USB_ID(0x0582, 0x0003), 0, "%s Part A" },
-       { USB_ID(0x0582, 0x0003), 1, "%s Part B" },
-       { USB_ID(0x0582, 0x0003), 2, "%s Part C" },
-       { USB_ID(0x0582, 0x0003), 3, "%s Part D" },
-       { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" },
-       { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" },
+       SOUNDCANVAS_PORT(0x0582, 0x0003, 0, "%s Part A", 128),
+       SOUNDCANVAS_PORT(0x0582, 0x0003, 1, "%s Part B", 128),
+       SOUNDCANVAS_PORT(0x0582, 0x0003, 2, "%s Part C", 128),
+       SOUNDCANVAS_PORT(0x0582, 0x0003, 3, "%s Part D", 128),
+       EXTERNAL_PORT(0x0582, 0x0003, 4, "%s MIDI 1"),
+       EXTERNAL_PORT(0x0582, 0x0003, 5, "%s MIDI 2"),
        /* Roland U-8 */
-       { USB_ID(0x0582, 0x0004), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x0004), 1, "%s Control" },
+       EXTERNAL_PORT(0x0582, 0x0004, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0004, 1, "%s Control"),
        /* Roland SC-8820 */
-       { USB_ID(0x0582, 0x0007), 0, "%s Part A" },
-       { USB_ID(0x0582, 0x0007), 1, "%s Part B" },
-       { USB_ID(0x0582, 0x0007), 2, "%s MIDI" },
+       SOUNDCANVAS_PORT(0x0582, 0x0007, 0, "%s Part A", 64),
+       SOUNDCANVAS_PORT(0x0582, 0x0007, 1, "%s Part B", 64),
+       EXTERNAL_PORT(0x0582, 0x0007, 2, "%s MIDI"),
        /* Roland SK-500 */
-       { USB_ID(0x0582, 0x000b), 0, "%s Part A" },
-       { USB_ID(0x0582, 0x000b), 1, "%s Part B" },
-       { USB_ID(0x0582, 0x000b), 2, "%s MIDI" },
+       SOUNDCANVAS_PORT(0x0582, 0x000b, 0, "%s Part A", 64),
+       SOUNDCANVAS_PORT(0x0582, 0x000b, 1, "%s Part B", 64),
+       EXTERNAL_PORT(0x0582, 0x000b, 2, "%s MIDI"),
        /* Roland SC-D70 */
-       { USB_ID(0x0582, 0x000c), 0, "%s Part A" },
-       { USB_ID(0x0582, 0x000c), 1, "%s Part B" },
-       { USB_ID(0x0582, 0x000c), 2, "%s MIDI" },
+       SOUNDCANVAS_PORT(0x0582, 0x000c, 0, "%s Part A", 64),
+       SOUNDCANVAS_PORT(0x0582, 0x000c, 1, "%s Part B", 64),
+       EXTERNAL_PORT(0x0582, 0x000c, 2, "%s MIDI"),
        /* Edirol UM-880 */
-       { USB_ID(0x0582, 0x0014), 8, "%s Control" },
+       CONTROL_PORT(0x0582, 0x0014, 8, "%s Control"),
        /* Edirol SD-90 */
-       { USB_ID(0x0582, 0x0016), 0, "%s Part A" },
-       { USB_ID(0x0582, 0x0016), 1, "%s Part B" },
-       { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" },
-       { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" },
+       ROLAND_SYNTH_PORT(0x0582, 0x0016, 0, "%s Part A", 128),
+       ROLAND_SYNTH_PORT(0x0582, 0x0016, 1, "%s Part B", 128),
+       EXTERNAL_PORT(0x0582, 0x0016, 2, "%s MIDI 1"),
+       EXTERNAL_PORT(0x0582, 0x0016, 3, "%s MIDI 2"),
        /* Edirol UM-550 */
-       { USB_ID(0x0582, 0x0023), 5, "%s Control" },
+       CONTROL_PORT(0x0582, 0x0023, 5, "%s Control"),
        /* Edirol SD-20 */
-       { USB_ID(0x0582, 0x0027), 0, "%s Part A" },
-       { USB_ID(0x0582, 0x0027), 1, "%s Part B" },
-       { USB_ID(0x0582, 0x0027), 2, "%s MIDI" },
+       ROLAND_SYNTH_PORT(0x0582, 0x0027, 0, "%s Part A", 64),
+       ROLAND_SYNTH_PORT(0x0582, 0x0027, 1, "%s Part B", 64),
+       EXTERNAL_PORT(0x0582, 0x0027, 2, "%s MIDI"),
        /* Edirol SD-80 */
-       { USB_ID(0x0582, 0x0029), 0, "%s Part A" },
-       { USB_ID(0x0582, 0x0029), 1, "%s Part B" },
-       { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" },
-       { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" },
+       ROLAND_SYNTH_PORT(0x0582, 0x0029, 0, "%s Part A", 128),
+       ROLAND_SYNTH_PORT(0x0582, 0x0029, 1, "%s Part B", 128),
+       EXTERNAL_PORT(0x0582, 0x0029, 2, "%s MIDI 1"),
+       EXTERNAL_PORT(0x0582, 0x0029, 3, "%s MIDI 2"),
        /* Edirol UA-700 */
-       { USB_ID(0x0582, 0x002b), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x002b), 1, "%s Control" },
+       EXTERNAL_PORT(0x0582, 0x002b, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x002b, 1, "%s Control"),
        /* Roland VariOS */
-       { USB_ID(0x0582, 0x002f), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" },
-       { USB_ID(0x0582, 0x002f), 2, "%s Sync" },
+       EXTERNAL_PORT(0x0582, 0x002f, 0, "%s MIDI"),
+       EXTERNAL_PORT(0x0582, 0x002f, 1, "%s External MIDI"),
+       EXTERNAL_PORT(0x0582, 0x002f, 2, "%s Sync"),
        /* Edirol PCR */
-       { USB_ID(0x0582, 0x0033), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x0033), 1, "%s 1" },
-       { USB_ID(0x0582, 0x0033), 2, "%s 2" },
+       EXTERNAL_PORT(0x0582, 0x0033, 0, "%s MIDI"),
+       EXTERNAL_PORT(0x0582, 0x0033, 1, "%s 1"),
+       EXTERNAL_PORT(0x0582, 0x0033, 2, "%s 2"),
        /* BOSS GS-10 */
-       { USB_ID(0x0582, 0x003b), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x003b), 1, "%s Control" },
+       EXTERNAL_PORT(0x0582, 0x003b, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x003b, 1, "%s Control"),
        /* Edirol UA-1000 */
-       { USB_ID(0x0582, 0x0044), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x0044), 1, "%s Control" },
+       EXTERNAL_PORT(0x0582, 0x0044, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0044, 1, "%s Control"),
        /* Edirol UR-80 */
-       { USB_ID(0x0582, 0x0048), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x0048), 1, "%s 1" },
-       { USB_ID(0x0582, 0x0048), 2, "%s 2" },
+       EXTERNAL_PORT(0x0582, 0x0048, 0, "%s MIDI"),
+       EXTERNAL_PORT(0x0582, 0x0048, 1, "%s 1"),
+       EXTERNAL_PORT(0x0582, 0x0048, 2, "%s 2"),
        /* Edirol PCR-A */
-       { USB_ID(0x0582, 0x004d), 0, "%s MIDI" },
-       { USB_ID(0x0582, 0x004d), 1, "%s 1" },
-       { USB_ID(0x0582, 0x004d), 2, "%s 2" },
+       EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),
+       EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),
+       EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"),
        /* Edirol UM-3EX */
-       { USB_ID(0x0582, 0x009a), 3, "%s Control" },
+       CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"),
        /* M-Audio MidiSport 8x8 */
-       { USB_ID(0x0763, 0x1031), 8, "%s Control" },
-       { USB_ID(0x0763, 0x1033), 8, "%s Control" },
+       CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),
+       CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"),
        /* MOTU Fastlane */
-       { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" },
-       { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" },
+       EXTERNAL_PORT(0x07fd, 0x0001, 0, "%s MIDI A"),
+       EXTERNAL_PORT(0x07fd, 0x0001, 1, "%s MIDI B"),
        /* Emagic Unitor8/AMT8/MT4 */
-       { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" },
-       { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" },
-       { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" },
+       EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
+       EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
+       EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
 };
 
+static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) {
+               if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id &&
+                   snd_usbmidi_port_info[i].port == number)
+                       return &snd_usbmidi_port_info[i];
+       }
+       return NULL;
+}
+
+static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number,
+                                     struct snd_seq_port_info *seq_port_info)
+{
+       struct snd_usb_midi *umidi = rmidi->private_data;
+       struct port_info *port_info;
+
+       /* TODO: read port flags from descriptors */
+       port_info = find_port_info(umidi, number);
+       if (port_info) {
+               seq_port_info->type = port_info->seq_flags;
+               seq_port_info->midi_voices = port_info->voices;
+       }
+}
+
 static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
                                       int stream, int number,
                                       struct snd_rawmidi_substream ** rsubstream)
 {
-       int i;
+       struct port_info *port_info;
        const char *name_format;
 
        struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number);
@@ -1110,14 +1171,8 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi,
        }
 
        /* TODO: read port name from jack descriptor */
-       name_format = "%s MIDI %d";
-       for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) {
-               if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id &&
-                   snd_usbmidi_port_names[i].port == number) {
-                       name_format = snd_usbmidi_port_names[i].name_format;
-                       break;
-               }
-       }
+       port_info = find_port_info(umidi, number);
+       name_format = port_info ? port_info->name : "%s MIDI %d";
        snprintf(substream->name, sizeof(substream->name),
                 name_format, umidi->chip->card->shortname, number + 1);
 
@@ -1358,7 +1413,7 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
        for (cs_desc = hostif->extra;
             cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
             cs_desc += cs_desc[0]) {
-               if (cs_desc[1] == CS_AUDIO_INTERFACE) {
+               if (cs_desc[1] == USB_DT_CS_INTERFACE) {
                        if (cs_desc[2] == MIDI_IN_JACK)
                                endpoint->in_cables = (endpoint->in_cables << 1) | 1;
                        else if (cs_desc[2] == MIDI_OUT_JACK)
@@ -1457,6 +1512,10 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
        return 0;
 }
 
+static struct snd_rawmidi_global_ops snd_usbmidi_ops = {
+       .get_port_info = snd_usbmidi_get_port_info,
+};
+
 static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,
                                      int out_ports, int in_ports)
 {
@@ -1472,6 +1531,7 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,
        rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
                            SNDRV_RAWMIDI_INFO_INPUT |
                            SNDRV_RAWMIDI_INFO_DUPLEX;
+       rmidi->ops = &snd_usbmidi_ops;
        rmidi->private_data = umidi;
        rmidi->private_free = snd_usbmidi_rawmidi_free;
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops);
index ce86283ee0fa6ded6c992aa24af05980e8a3f627..491e975a0c87ef8d2a5a820beba42da61150cdac 100644 (file)
 /* ignore error from controls - for debugging */
 /* #define IGNORE_CTL_ERROR */
 
+/*
+ * Sound Blaster remote control configuration
+ *
+ * format of remote control data:
+ * Extigy:       xx 00
+ * Audigy 2 NX:  06 80 xx 00 00 00
+ * Live! 24-bit: 06 80 xx yy 22 83
+ */
+static const struct rc_config {
+       u32 usb_id;
+       u8  offset;
+       u8  length;
+       u8  packet_length;
+       u8  mute_mixer_id;
+       u32 mute_code;
+} rc_configs[] = {
+       { USB_ID(0x041e, 0x3000), 0, 1, 2,  18, 0x0013 }, /* Extigy       */
+       { USB_ID(0x041e, 0x3020), 2, 1, 6,  18, 0x0013 }, /* Audigy 2 NX  */
+       { USB_ID(0x041e, 0x3040), 2, 2, 6,  2,  0x6e91 }, /* Live! 24-bit */
+};
+
 struct usb_mixer_interface {
        struct snd_usb_audio *chip;
        unsigned int ctrlif;
@@ -55,11 +76,7 @@ struct usb_mixer_interface {
        struct usb_mixer_elem_info **id_elems; /* array[256], indexed by unit id */
 
        /* Sound Blaster remote control stuff */
-       enum {
-               RC_NONE,
-               RC_EXTIGY,
-               RC_AUDIGY2NX,
-       } rc_type;
+       const struct rc_config *rc_cfg;
        unsigned long rc_hwdep_open;
        u32 rc_code;
        wait_queue_head_t rc_waitq;
@@ -1647,7 +1664,7 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer,
 static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
                                        int unitid)
 {
-       if (mixer->rc_type == RC_NONE)
+       if (!mixer->rc_cfg)
                return;
        /* unit ids specific to Extigy/Audigy 2 NX: */
        switch (unitid) {
@@ -1732,20 +1749,19 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb,
                                                 struct pt_regs *regs)
 {
        struct usb_mixer_interface *mixer = urb->context;
-       /*
-        * format of remote control data:
-        * Extigy:      xx 00
-        * Audigy 2 NX: 06 80 xx 00 00 00
-        */
-       int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2;
+       const struct rc_config *rc = mixer->rc_cfg;
        u32 code;
 
-       if (urb->status < 0 || urb->actual_length <= offset)
+       if (urb->status < 0 || urb->actual_length < rc->packet_length)
                return;
-       code = mixer->rc_buffer[offset];
+
+       code = mixer->rc_buffer[rc->offset];
+       if (rc->length == 2)
+               code |= mixer->rc_buffer[rc->offset + 1] << 8;
+
        /* the Mute button actually changes the mixer control */
-       if (code == 13)
-               snd_usb_mixer_notify_id(mixer, 18);
+       if (code == rc->mute_code)
+               snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id);
        mixer->rc_code = code;
        wmb();
        wake_up(&mixer->rc_waitq);
@@ -1801,21 +1817,17 @@ static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *f
 static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
 {
        struct snd_hwdep *hwdep;
-       int err, len;
+       int err, len, i;
 
-       switch (mixer->chip->usb_id) {
-       case USB_ID(0x041e, 0x3000):
-               mixer->rc_type = RC_EXTIGY;
-               len = 2;
-               break;
-       case USB_ID(0x041e, 0x3020):
-               mixer->rc_type = RC_AUDIGY2NX;
-               len = 6;
-               break;
-       default:
+       for (i = 0; i < ARRAY_SIZE(rc_configs); ++i)
+               if (rc_configs[i].usb_id == mixer->chip->usb_id)
+                       break;
+       if (i >= ARRAY_SIZE(rc_configs))
                return 0;
-       }
+       mixer->rc_cfg = &rc_configs[i];
 
+       len = mixer->rc_cfg->packet_length;
+       
        init_waitqueue_head(&mixer->rc_waitq);
        err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep);
        if (err < 0)
@@ -1998,7 +2010,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
                        goto _error;
                if (!snd_card_proc_new(chip->card, "audigy2nx", &entry))
-                       snd_info_set_text_ops(entry, mixer, 1024,
+                       snd_info_set_text_ops(entry, mixer,
                                              snd_audigy2nx_proc_read);
        }
 
index fe67a92e2a1a355ccbd36acb1ce2c6dcab7b2777..88b72b52590f44c4566864577223720b2d5a7c98 100644 (file)
@@ -632,7 +632,7 @@ static int usX2Y_pcms_lock_check(struct snd_card *card)
                for (s = 0; s < 2; ++s) {
                        struct snd_pcm_substream *substream;
                        substream = pcm->streams[s].substream;
-                       if (substream && substream->ffile != NULL)
+                       if (SUBSTREAM_BUSY(substream))
                                err = -EBUSY;
                }
        }