Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 6 Feb 2008 21:54:09 +0000 (13:54 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 6 Feb 2008 21:54:09 +0000 (13:54 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86:
  x86: fix deadlock, make pgd_lock irq-safe
  virtio: fix trivial build bug
  x86: fix mttr trimming
  x86: delay CPA self-test and repeat it
  x86: fix 64-bit sections
  generic: add __FINITDATA
  x86: remove suprious ifdefs from pageattr.c
  x86: mark the .rodata section also NX
  x86: fix iret exception recovery on 64-bit
  cpuidle: dubious one-bit signed bitfield in cpuidle.h
  x86: fix sparse warnings in powernow-k8.c
  x86: fix sparse error in traps_32.c
  x86: trivial sparse/checkpatch in quirks.c
  x86 ptrace: disallow null cs/ss
  MAINTAINERS: RDC R-321x SoC maintainer
  brk randomization: introduce CONFIG_COMPAT_BRK
  brk: check the lower bound properly
  x86: remove X2 workaround
  x86: make spurious fault handler aware of large mappings
  x86: make traps on entry code be debuggable in user space, 64-bit

476 files changed:
Documentation/BUG-HUNTING
Documentation/DocBook/kernel-locking.tmpl
Documentation/fb/deferred_io.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/proc.txt
Documentation/kprobes.txt
Documentation/kref.txt
Documentation/md.txt
Documentation/rtc.txt
Documentation/sysctl/fs.txt
Documentation/unaligned-memory-access.txt [new file with mode: 0644]
Documentation/w1/masters/00-INDEX
Documentation/w1/masters/w1-gpio [new file with mode: 0644]
MAINTAINERS
arch/alpha/Kconfig.debug
arch/alpha/defconfig
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/smp.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-rpc/riscpc.c
arch/avr32/lib/delay.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/cm_bf537.c
arch/blackfin/mach-bf537/boards/generic_board.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/frv/kernel/setup.c
arch/h8300/kernel/irq.c
arch/ia64/kernel/smpboot.c
arch/ia64/sn/pci/pcibr/pcibr_provider.c
arch/m68k/amiga/chipram.c
arch/m68k/amiga/cia.c
arch/m68knommu/lib/memcpy.c
arch/mips/au1000/common/gpio.c
arch/mips/kernel/smp.c
arch/mips/kernel/sysirix.c
arch/parisc/Kconfig.debug
arch/parisc/configs/a500_defconfig
arch/powerpc/kernel/time.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/ppc/8260_io/enet.c
arch/ppc/8260_io/fcc_enet.c
arch/ppc/kernel/vmlinux.lds.S
arch/ppc/platforms/prep_setup.c
arch/sh/boards/landisk/setup.c
arch/sh/boards/lboxre2/setup.c
arch/sh/boards/renesas/r7780rp/setup.c
arch/sh/boards/renesas/rts7751r2d/setup.c
arch/sh/boards/renesas/sdk7780/setup.c
arch/sh/boards/se/7722/setup.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/systbls.S
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/iommu.c
arch/sparc64/kernel/iommu_common.c [deleted file]
arch/sparc64/kernel/iommu_common.h
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/solaris/fs.c
arch/sparc64/solaris/timod.c
arch/x86/Kconfig
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cyrix.c
arch/x86/kernel/smpboot_32.c
arch/x86/lib/delay_32.c
arch/x86/lib/delay_64.c
arch/x86/mach-voyager/voyager_smp.c
arch/xtensa/kernel/time.c
crypto/async_tx/async_memcpy.c
crypto/async_tx/async_memset.c
crypto/async_tx/async_tx.c
crypto/async_tx/async_xor.c
drivers/ata/ahci.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/pata_of_platform.c
drivers/ata/pata_platform.c
drivers/ata/sata_fsl.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_via.c
drivers/base/cpu.c
drivers/block/ataflop.c
drivers/block/cciss.c
drivers/block/loop.c
drivers/block/paride/pt.c
drivers/block/pktcdvd.c
drivers/block/rd.c
drivers/cdrom/cdrom.c
drivers/char/Kconfig
drivers/char/hvc_console.c
drivers/char/hvcs.c
drivers/char/hw_random/via-rng.c
drivers/char/i8k.c
drivers/char/ip27-rtc.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/lp.c
drivers/char/mxser.c
drivers/char/mxser_new.c
drivers/char/n_tty.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/random.c
drivers/char/riscom8.c
drivers/char/ser_a2232.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_infineon.c
drivers/char/tty_io.c
drivers/char/vt.c
drivers/dma/Kconfig
drivers/dma/dmaengine.c
drivers/dma/ioat_dma.c
drivers/dma/iop-adma.c
drivers/firmware/dcdbas.c
drivers/firmware/dmi-id.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/pca9539.c [deleted file]
drivers/gpio/pca953x.c [new file with mode: 0644]
drivers/ide/ide-probe.c
drivers/ide/legacy/ide_platform.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/isdn/act2000/module.c
drivers/isdn/gigaset/asyncdata.c
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/common.c
drivers/isdn/gigaset/ev-layer.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/gigaset/interface.c
drivers/isdn/gigaset/isocdata.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/hardware/eicon/debug.c
drivers/isdn/hardware/eicon/diva.c
drivers/isdn/hardware/eicon/message.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/i4l/isdn_ttyfax.c
drivers/isdn/icn/icn.c
drivers/isdn/isdnloop/isdnloop.c
drivers/md/bitmap.c
drivers/md/faulty.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/mktables.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid6test/test.c
drivers/media/video/Makefile
drivers/media/video/tvmixer.c [deleted file]
drivers/misc/asus-laptop.c
drivers/misc/fujitsu-laptop.c
drivers/misc/lkdtm.c
drivers/misc/msi-laptop.c
drivers/misc/phantom.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/phram.c
drivers/mtd/maps/mtx-1_flash.c
drivers/net/forcedeth.c
drivers/net/gianfar_mii.c
drivers/net/iseries_veth.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/mv643xx_eth.c
drivers/net/pppol2tp.c
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/tlan.c
drivers/net/tulip/xircom_cb.c
drivers/net/ucc_geth_mii.c
drivers/net/virtio_net.c
drivers/net/wan/hdlc.c
drivers/net/wan/hdlc_cisco.c
drivers/net/wan/hdlc_fr.c
drivers/net/wan/hdlc_ppp.c
drivers/net/wan/hdlc_raw.c
drivers/net/wan/hdlc_raw_eth.c
drivers/net/wan/hdlc_x25.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/dma.h
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/pio.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/b43legacy/xmit.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/parport/parport_pc.c
drivers/parport/parport_serial.c
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
drivers/pci/intel-iommu.h
drivers/pci/iova.c
drivers/pci/iova.h
drivers/pnp/driver.c
drivers/pnp/interface.c
drivers/pnp/manager.c
drivers/pnp/pnpacpi/rsparser.c
drivers/pnp/pnpbios/core.c
drivers/pnp/pnpbios/rsparser.c
drivers/pnp/quirks.c
drivers/ps3/ps3av.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-at91sam9.c [new file with mode: 0644]
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1302.c [new file with mode: 0644]
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1511.c [new file with mode: 0644]
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-r9701.c [new file with mode: 0644]
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sysfs.c
drivers/s390/sysinfo.c
drivers/scsi/a2091.c
drivers/scsi/a3000.c
drivers/scsi/aic7xxx_old.c
drivers/scsi/gvp11.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/dz.c
drivers/serial/imx.c
drivers/serial/sc26xx.c [new file with mode: 0644]
drivers/serial/uartlite.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel_spi.c
drivers/spi/omap2_mcspi.c
drivers/spi/pxa2xx_spi.c
drivers/spi/spi.c
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_imx.c
drivers/spi/spi_s3c24xx.c
drivers/spi/spi_s3c24xx_gpio.c
drivers/spi/spi_sh_sci.c [new file with mode: 0644]
drivers/uio/uio.c
drivers/video/atmel_lcdfb.c
drivers/video/backlight/Kconfig
drivers/video/bf54x-lq043fb.c
drivers/video/console/bitblit.c
drivers/video/console/fbcon.c
drivers/video/console/fbcon.h
drivers/video/console/fbcon_ccw.c
drivers/video/console/fbcon_cw.c
drivers/video/console/fbcon_ud.c
drivers/video/console/fonts.c
drivers/video/console/tileblit.c
drivers/video/console/vgacon.c
drivers/video/fb_defio.c
drivers/video/fb_draw.h
drivers/video/fbmon.c
drivers/video/geode/lxfb_core.c
drivers/video/hpfb.c
drivers/video/i810/i810_main.c
drivers/video/igafb.c
drivers/video/intelfb/intelfbhw.c
drivers/video/neofb.c
drivers/video/nvidia/nvidia.c
drivers/video/pm2fb.c
drivers/video/pm3fb.c
drivers/video/pmag-aa-fb.c
drivers/video/ps3fb.c
drivers/video/s3c2410fb.c
drivers/video/s3c2410fb.h
drivers/video/sis/sis_main.c
drivers/video/sm501fb.c
drivers/video/tdfxfb.c
drivers/video/uvesafb.c
drivers/video/vermilion/vermilion.c
drivers/w1/masters/Kconfig
drivers/w1/masters/Makefile
drivers/w1/masters/w1-gpio.c [new file with mode: 0644]
drivers/w1/slaves/w1_therm.c
drivers/w1/w1.c
fs/block_dev.c
fs/compat.c
fs/dcache.c
fs/dquot.c
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/ecryptfs/mmap.c
fs/ecryptfs/read_write.c
fs/ecryptfs/super.c
fs/eventfd.c
fs/ext2/balloc.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/ext2/super.c
fs/ext3/balloc.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/super.c
fs/ext4/balloc.c
fs/ext4/inode.c
fs/ext4/super.c
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/file.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/hfs/bfind.c
fs/hfs/brec.c
fs/hfs/btree.c
fs/hfs/hfs.h
fs/hfs/super.c
fs/inotify.c
fs/inotify_user.c
fs/jbd/journal.c
fs/jbd/recovery.c
fs/jbd2/recovery.c
fs/namei.c
fs/namespace.c
fs/ncpfs/inode.c
fs/partitions/Kconfig
fs/pnode.c
fs/proc/proc_misc.c
fs/reiserfs/prints.c
fs/reiserfs/xattr.c
fs/select.c
fs/signalfd.c
fs/smbfs/sock.c
fs/utimes.c
include/asm-arm/arch-iop13xx/adma.h
include/asm-arm/arch-s3c2410/regs-lcd.h
include/asm-arm/arch-s3c2410/spi-gpio.h
include/asm-arm/arch-s3c2410/spi.h
include/asm-arm/hardware/iop3xx-adma.h
include/asm-avr32/delay.h
include/asm-avr32/timex.h
include/asm-blackfin/io.h
include/asm-generic/cputime.h
include/asm-generic/sections.h
include/asm-h8300/io.h
include/asm-h8300/virtconvert.h
include/asm-m32r/delay.h
include/asm-m68k/pgtable.h
include/asm-m68knommu/io.h
include/asm-powerpc/cputime.h
include/asm-powerpc/dma.h
include/asm-powerpc/paca.h
include/asm-powerpc/ps3av.h
include/asm-s390/cputime.h
include/asm-sh/delay.h
include/asm-sparc/unistd.h
include/asm-sparc64/io.h
include/asm-sparc64/timex.h
include/asm-sparc64/unistd.h
include/asm-v850/io.h
include/asm-x86/delay.h
include/asm-x86/timex.h
include/linux/ac97_codec.h
include/linux/acct.h
include/linux/async_tx.h
include/linux/ata_platform.h [new file with mode: 0644]
include/linux/compat.h
include/linux/dmaengine.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/hash.h
include/linux/hdlc.h
include/linux/i2c/pca9539.h [deleted file]
include/linux/i2c/pca953x.h [new file with mode: 0644]
include/linux/if_vlan.h
include/linux/interrupt.h
include/linux/isdn.h
include/linux/jbd.h
include/linux/kernel.h
include/linux/kprobes.h
include/linux/libata.h
include/linux/log2.h
include/linux/loop.h
include/linux/lp.h
include/linux/pata_platform.h [deleted file]
include/linux/pci_ids.h
include/linux/percpu.h
include/linux/pkt_cls.h
include/linux/pnp.h
include/linux/ptrace.h
include/linux/raid/bitmap.h
include/linux/raid/md_k.h
include/linux/rcupdate.h
include/linux/sched.h
include/linux/signal.h
include/linux/sm501.h
include/linux/ssb/ssb.h
include/linux/timex.h
include/linux/tty.h
include/linux/vt_kern.h
include/linux/w1-gpio.h [new file with mode: 0644]
include/video/atmel_lcdc.h
init/calibrate.c
init/do_mounts.c
init/initramfs.c
init/main.c
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
kernel/exit.c
kernel/fork.c
kernel/kallsyms.c
kernel/kprobes.c
kernel/notifier.c
kernel/params.c
kernel/printk.c
kernel/ptrace.c
kernel/relay.c
kernel/signal.c
kernel/srcu.c
kernel/stop_machine.c
kernel/sys.c
kernel/sysctl.c
kernel/test_kprobes.c
kernel/time.c
kernel/time/clocksource.c
kernel/timer.c
lib/extable.c
lib/smp_processor_id.c
mm/allocpercpu.c
net/ipv4/ipvs/ip_vs_wrr.c
net/mac80211/Kconfig
net/sched/cls_flow.c
net/sched/em_meta.c
scripts/checkstack.pl
scripts/kallsyms.c
security/Kconfig
security/security.c
security/selinux/include/security.h
security/selinux/ss/services.c
sound/oss/Makefile
sound/oss/ac97_codec.c
sound/oss/btaudio.c [deleted file]
sound/oss/cs4232.c [deleted file]
sound/oss/dmasound/Kconfig
sound/oss/dmasound/dmasound_paula.c
sound/oss/i810_audio.c [deleted file]
sound/oss/pss.c
sound/oss/sb_common.c
sound/oss/trident.c
sound/oss/via82cxxx_audio.c [deleted file]

index 6c81675..65022a8 100644 (file)
@@ -214,6 +214,23 @@ And recompile the kernel with CONFIG_DEBUG_INFO enabled:
   gdb vmlinux
   (gdb) p vt_ioctl
   (gdb) l *(0x<address of vt_ioctl> + 0xda8)
+or, as one command
+  (gdb) l *(vt_ioctl + 0xda8)
+
+If you have a call trace, such as :-
+>Call Trace:
+> [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
+> [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
+> [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
+> ...
+this shows the problem in the :jbd: module. You can load that module in gdb
+and list the relevant code.
+  gdb fs/jbd/jbd.ko
+  (gdb) p log_wait_commit
+  (gdb) l *(0x<address> + 0xa3)
+or
+  (gdb) l *(log_wait_commit + 0xa3)
+
 
 Another very useful option of the Kernel Hacking section in menuconfig is
 Debug memory allocations. This will help you see whether data has been
index 01825ee..2e9d6b4 100644 (file)
@@ -717,7 +717,7 @@ used, and when it gets full, throws out the least used one.
     <para>
 For our first example, we assume that all operations are in user
 context (ie. from system calls), so we can sleep.  This means we can
-use a semaphore to protect the cache and all the objects within
+use a mutex to protect the cache and all the objects within
 it.  Here's the code:
     </para>
 
@@ -725,7 +725,7 @@ it.  Here's the code:
 #include &lt;linux/list.h&gt;
 #include &lt;linux/slab.h&gt;
 #include &lt;linux/string.h&gt;
-#include &lt;asm/semaphore.h&gt;
+#include &lt;linux/mutex.h&gt;
 #include &lt;asm/errno.h&gt;
 
 struct object
@@ -737,7 +737,7 @@ struct object
 };
 
 /* Protects the cache, cache_num, and the objects within it */
-static DECLARE_MUTEX(cache_lock);
+static DEFINE_MUTEX(cache_lock);
 static LIST_HEAD(cache);
 static unsigned int cache_num = 0;
 #define MAX_CACHE_SIZE 10
@@ -789,17 +789,17 @@ int cache_add(int id, const char *name)
         obj-&gt;id = id;
         obj-&gt;popularity = 0;
 
-        down(&amp;cache_lock);
+        mutex_lock(&amp;cache_lock);
         __cache_add(obj);
-        up(&amp;cache_lock);
+        mutex_unlock(&amp;cache_lock);
         return 0;
 }
 
 void cache_delete(int id)
 {
-        down(&amp;cache_lock);
+        mutex_lock(&amp;cache_lock);
         __cache_delete(__cache_find(id));
-        up(&amp;cache_lock);
+        mutex_unlock(&amp;cache_lock);
 }
 
 int cache_find(int id, char *name)
@@ -807,13 +807,13 @@ int cache_find(int id, char *name)
         struct object *obj;
         int ret = -ENOENT;
 
-        down(&amp;cache_lock);
+        mutex_lock(&amp;cache_lock);
         obj = __cache_find(id);
         if (obj) {
                 ret = 0;
                 strcpy(name, obj-&gt;name);
         }
-        up(&amp;cache_lock);
+        mutex_unlock(&amp;cache_lock);
         return ret;
 }
 </programlisting>
@@ -853,7 +853,7 @@ The change is shown below, in standard patch format: the
          int popularity;
  };
 
--static DECLARE_MUTEX(cache_lock);
+-static DEFINE_MUTEX(cache_lock);
 +static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED;
  static LIST_HEAD(cache);
  static unsigned int cache_num = 0;
@@ -870,22 +870,22 @@ The change is shown below, in standard patch format: the
          obj-&gt;id = id;
          obj-&gt;popularity = 0;
 
--        down(&amp;cache_lock);
+-        mutex_lock(&amp;cache_lock);
 +        spin_lock_irqsave(&amp;cache_lock, flags);
          __cache_add(obj);
--        up(&amp;cache_lock);
+-        mutex_unlock(&amp;cache_lock);
 +        spin_unlock_irqrestore(&amp;cache_lock, flags);
          return 0;
  }
 
  void cache_delete(int id)
  {
--        down(&amp;cache_lock);
+-        mutex_lock(&amp;cache_lock);
 +        unsigned long flags;
 +
 +        spin_lock_irqsave(&amp;cache_lock, flags);
          __cache_delete(__cache_find(id));
--        up(&amp;cache_lock);
+-        mutex_unlock(&amp;cache_lock);
 +        spin_unlock_irqrestore(&amp;cache_lock, flags);
  }
 
@@ -895,14 +895,14 @@ The change is shown below, in standard patch format: the
          int ret = -ENOENT;
 +        unsigned long flags;
 
--        down(&amp;cache_lock);
+-        mutex_lock(&amp;cache_lock);
 +        spin_lock_irqsave(&amp;cache_lock, flags);
          obj = __cache_find(id);
          if (obj) {
                  ret = 0;
                  strcpy(name, obj-&gt;name);
          }
--        up(&amp;cache_lock);
+-        mutex_unlock(&amp;cache_lock);
 +        spin_unlock_irqrestore(&amp;cache_lock, flags);
          return ret;
  }
index 63883a8..7483283 100644 (file)
@@ -7,10 +7,10 @@ IO. The following example may be a useful explanation of how one such setup
 works:
 
 - userspace app like Xfbdev mmaps framebuffer
-- deferred IO and driver sets up nopage and page_mkwrite handlers
+- deferred IO and driver sets up fault and page_mkwrite handlers
 - userspace app tries to write to mmaped vaddress
-- we get pagefault and reach nopage handler
-- nopage handler finds and returns physical page
+- we get pagefault and reach fault handler
+- fault handler finds and returns physical page
 - we get page_mkwrite where we add this page to a list
 - schedule a workqueue task to be run after a delay
 - app continues writing to that page with no additional cost. this is
index a7d9d17..68ce130 100644 (file)
@@ -208,13 +208,6 @@ Who:       Randy Dunlap <randy.dunlap@oracle.com>
 
 ---------------------------
 
-What:  drivers depending on OSS_OBSOLETE
-When:  options in 2.6.23, code in 2.6.25
-Why:   obsolete OSS drivers
-Who:   Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
 What: libata spindown skipping and warning
 When: Dec 2008
 Why:  Some halt(8) implementations synchronize caches for and spin
index e2799b5..5681e2f 100644 (file)
@@ -1029,6 +1029,14 @@ nr_inodes
 Denotes the  number  of  inodes the system has allocated. This number will
 grow and shrink dynamically.
 
+nr_open
+-------
+
+Denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on RLIMIT_NOFILE
+resource limit.
+
 nr_free_inodes
 --------------
 
index 53a6389..30c1017 100644 (file)
@@ -96,7 +96,9 @@ or in registers (e.g., for x86_64 or for an i386 fastcall function).
 The jprobe will work in either case, so long as the handler's
 prototype matches that of the probed function.
 
-1.3 How Does a Return Probe Work?
+1.3 Return Probes
+
+1.3.1 How Does a Return Probe Work?
 
 When you call register_kretprobe(), Kprobes establishes a kprobe at
 the entry to the function.  When the probed function is called and this
@@ -107,9 +109,9 @@ At boot time, Kprobes registers a kprobe at the trampoline.
 
 When the probed function executes its return instruction, control
 passes to the trampoline and that probe is hit.  Kprobes' trampoline
-handler calls the user-specified handler associated with the kretprobe,
-then sets the saved instruction pointer to the saved return address,
-and that's where execution resumes upon return from the trap.
+handler calls the user-specified return handler associated with the
+kretprobe, then sets the saved instruction pointer to the saved return
+address, and that's where execution resumes upon return from the trap.
 
 While the probed function is executing, its return address is
 stored in an object of type kretprobe_instance.  Before calling
@@ -131,6 +133,30 @@ zero when the return probe is registered, and is incremented every
 time the probed function is entered but there is no kretprobe_instance
 object available for establishing the return probe.
 
+1.3.2 Kretprobe entry-handler
+
+Kretprobes also provides an optional user-specified handler which runs
+on function entry. This handler is specified by setting the entry_handler
+field of the kretprobe struct. Whenever the kprobe placed by kretprobe at the
+function entry is hit, the user-defined entry_handler, if any, is invoked.
+If the entry_handler returns 0 (success) then a corresponding return handler
+is guaranteed to be called upon function return. If the entry_handler
+returns a non-zero error then Kprobes leaves the return address as is, and
+the kretprobe has no further effect for that particular function instance.
+
+Multiple entry and return handler invocations are matched using the unique
+kretprobe_instance object associated with them. Additionally, a user
+may also specify per return-instance private data to be part of each
+kretprobe_instance object. This is especially useful when sharing private
+data between corresponding user entry and return handlers. The size of each
+private data object can be specified at kretprobe registration time by
+setting the data_size field of the kretprobe struct. This data can be
+accessed through the data field of each kretprobe_instance object.
+
+In case probed function is entered but there is no kretprobe_instance
+object available, then in addition to incrementing the nmissed count,
+the user entry_handler invocation is also skipped.
+
 2. Architectures Supported
 
 Kprobes, jprobes, and return probes are implemented on the following
@@ -274,6 +300,8 @@ of interest:
 - ret_addr: the return address
 - rp: points to the corresponding kretprobe object
 - task: points to the corresponding task struct
+- data: points to per return-instance private data; see "Kretprobe
+       entry-handler" for details.
 
 The regs_return_value(regs) macro provides a simple abstraction to
 extract the return value from the appropriate register as defined by
@@ -556,23 +584,52 @@ report failed calls to sys_open().
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
+#include <linux/ktime.h>
+
+/* per-instance private data */
+struct my_data {
+       ktime_t entry_stamp;
+};
 
 static const char *probed_func = "sys_open";
 
-/* Return-probe handler: If the probed function fails, log the return value. */
-static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+/* Timestamp function entry. */
+static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct my_data *data;
+
+       if(!current->mm)
+               return 1; /* skip kernel threads */
+
+       data = (struct my_data *)ri->data;
+       data->entry_stamp = ktime_get();
+       return 0;
+}
+
+/* If the probed function failed, log the return value and duration.
+ * Duration may turn out to be zero consistently, depending upon the
+ * granularity of time accounting on the platform. */
+static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        int retval = regs_return_value(regs);
+       struct my_data *data = (struct my_data *)ri->data;
+       s64 delta;
+       ktime_t now;
+
        if (retval < 0) {
-               printk("%s returns %d\n", probed_func, retval);
+               now = ktime_get();
+               delta = ktime_to_ns(ktime_sub(now, data->entry_stamp));
+               printk("%s: return val = %d (duration = %lld ns)\n",
+                      probed_func, retval, delta);
        }
        return 0;
 }
 
 static struct kretprobe my_kretprobe = {
-       .handler = ret_handler,
-       /* Probe up to 20 instances concurrently. */
-       .maxactive = 20
+       .handler = return_handler,
+       .entry_handler = entry_handler,
+       .data_size = sizeof(struct my_data),
+       .maxactive = 20, /* probe up to 20 instances concurrently */
 };
 
 static int __init kretprobe_init(void)
@@ -584,7 +641,7 @@ static int __init kretprobe_init(void)
                printk("register_kretprobe failed, returned %d\n", ret);
                return -1;
        }
-       printk("Planted return probe at %p\n", my_kretprobe.kp.addr);
+       printk("Kretprobe active on %s\n", my_kretprobe.kp.symbol_name);
        return 0;
 }
 
@@ -594,7 +651,7 @@ static void __exit kretprobe_exit(void)
        printk("kretprobe unregistered\n");
        /* nmissed > 0 suggests that maxactive was set too low. */
        printk("Missed probing %d instances of %s\n",
-               my_kretprobe.nmissed, probed_func);
+              my_kretprobe.nmissed, probed_func);
 }
 
 module_init(kretprobe_init)
index f38b59d..130b6e8 100644 (file)
@@ -141,10 +141,10 @@ The last rule (rule 3) is the nastiest one to handle.  Say, for
 instance, you have a list of items that are each kref-ed, and you wish
 to get the first one.  You can't just pull the first item off the list
 and kref_get() it.  That violates rule 3 because you are not already
-holding a valid pointer.  You must add locks or semaphores.  For
-instance:
+holding a valid pointer.  You must add a mutex (or some other lock).
+For instance:
 
-static DECLARE_MUTEX(sem);
+static DEFINE_MUTEX(mutex);
 static LIST_HEAD(q);
 struct my_data
 {
@@ -155,12 +155,12 @@ struct my_data
 static struct my_data *get_entry()
 {
        struct my_data *entry = NULL;
-       down(&sem);
+       mutex_lock(&mutex);
        if (!list_empty(&q)) {
                entry = container_of(q.next, struct my_q_entry, link);
                kref_get(&entry->refcount);
        }
-       up(&sem);
+       mutex_unlock(&mutex);
        return entry;
 }
 
@@ -174,9 +174,9 @@ static void release_entry(struct kref *ref)
 
 static void put_entry(struct my_data *entry)
 {
-       down(&sem);
+       mutex_lock(&mutex);
        kref_put(&entry->refcount, release_entry);
-       up(&sem);
+       mutex_unlock(&mutex);
 }
 
 The kref_put() return value is useful if you do not want to hold the
@@ -191,13 +191,13 @@ static void release_entry(struct kref *ref)
 
 static void put_entry(struct my_data *entry)
 {
-       down(&sem);
+       mutex_lock(&mutex);
        if (kref_put(&entry->refcount, release_entry)) {
                list_del(&entry->link);
-               up(&sem);
+               mutex_unlock(&mutex);
                kfree(entry);
        } else
-               up(&sem);
+               mutex_unlock(&mutex);
 }
 
 This is really more useful if you have to call other routines as part
index 5818628..396cdd9 100644 (file)
@@ -416,6 +416,16 @@ also have
      sectors in total that could need to be processed.  The two
      numbers are separated by a '/'  thus effectively showing one
      value, a fraction of the process that is complete.
+     A 'select' on this attribute will return when resync completes,
+     when it reaches the current sync_max (below) and possibly at
+     other times.
+
+   sync_max
+     This is a number of sectors at which point a resync/recovery
+     process will pause.  When a resync is active, the value can
+     only ever be increased, never decreased.  The value of 'max'
+     effectively disables the limit.
+
 
    sync_speed
      This shows the current actual speed, in K/sec, of the current
index e20b19c..8deffcd 100644 (file)
@@ -182,8 +182,8 @@ driver returns ENOIOCTLCMD.  Some common examples:
        since the frequency is stored in the irq_freq member of the rtc_device
        structure.  Your driver needs to initialize the irq_freq member during
        init.  Make sure you check the requested frequency is in range of your
-       hardware in the irq_set_freq function.  If you cannot actually change
-       the frequency, just return -ENOTTY.
+       hardware in the irq_set_freq function.  If it isn't, return -EINVAL.  If
+       you cannot actually change the frequency, do not define irq_set_freq.
 
 If all else fails, check out the rtc-test.c driver!
 
@@ -268,8 +268,8 @@ int main(int argc, char **argv)
                /* This read will block */
                retval = read(fd, &data, sizeof(unsigned long));
                if (retval == -1) {
-                       perror("read");
-                       exit(errno);
+                       perror("read");
+                       exit(errno);
                }
                fprintf(stderr, " %d",i);
                fflush(stderr);
@@ -326,11 +326,11 @@ test_READ:
                rtc_tm.tm_sec %= 60;
                rtc_tm.tm_min++;
        }
-       if  (rtc_tm.tm_min == 60) {
+       if (rtc_tm.tm_min == 60) {
                rtc_tm.tm_min = 0;
                rtc_tm.tm_hour++;
        }
-       if  (rtc_tm.tm_hour == 24)
+       if (rtc_tm.tm_hour == 24)
                rtc_tm.tm_hour = 0;
 
        retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
@@ -407,8 +407,8 @@ test_PIE:
                                        "\n...Periodic IRQ rate is fixed\n");
                                goto done;
                        }
-                       perror("RTC_IRQP_SET ioctl");
-                       exit(errno);
+                       perror("RTC_IRQP_SET ioctl");
+                       exit(errno);
                }
 
                fprintf(stderr, "\n%ldHz:\t", tmp);
@@ -417,27 +417,27 @@ test_PIE:
                /* Enable periodic interrupts */
                retval = ioctl(fd, RTC_PIE_ON, 0);
                if (retval == -1) {
-                       perror("RTC_PIE_ON ioctl");
-                       exit(errno);
+                       perror("RTC_PIE_ON ioctl");
+                       exit(errno);
                }
 
                for (i=1; i<21; i++) {
-                       /* This blocks */
-                       retval = read(fd, &data, sizeof(unsigned long));
-                       if (retval == -1) {
-                                      perror("read");
-                                      exit(errno);
-                       }
-                       fprintf(stderr, " %d",i);
-                       fflush(stderr);
-                       irqcount++;
+                       /* This blocks */
+                       retval = read(fd, &data, sizeof(unsigned long));
+                       if (retval == -1) {
+                               perror("read");
+                               exit(errno);
+                       }
+                       fprintf(stderr, " %d",i);
+                       fflush(stderr);
+                       irqcount++;
                }
 
                /* Disable periodic interrupts */
                retval = ioctl(fd, RTC_PIE_OFF, 0);
                if (retval == -1) {
-                       perror("RTC_PIE_OFF ioctl");
-                       exit(errno);
+                       perror("RTC_PIE_OFF ioctl");
+                       exit(errno);
                }
        }
 
index aa986a3..f992543 100644 (file)
@@ -23,6 +23,7 @@ Currently, these files are in /proc/sys/fs:
 - inode-max
 - inode-nr
 - inode-state
+- nr_open
 - overflowuid
 - overflowgid
 - suid_dumpable
@@ -91,6 +92,15 @@ usage of file handles and you don't need to increase the maximum.
 
 ==============================================================
 
+nr_open:
+
+This denotes the maximum number of file-handles a process can
+allocate. Default value is 1024*1024 (1048576) which should be
+enough for most machines. Actual limit depends on RLIMIT_NOFILE
+resource limit.
+
+==============================================================
+
 inode-max, inode-nr & inode-state:
 
 As with file handles, the kernel allocates the inode structures
diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt
new file mode 100644 (file)
index 0000000..6223eac
--- /dev/null
@@ -0,0 +1,226 @@
+UNALIGNED MEMORY ACCESSES
+=========================
+
+Linux runs on a wide variety of architectures which have varying behaviour
+when it comes to memory access. This document presents some details about
+unaligned accesses, why you need to write code that doesn't cause them,
+and how to write such code!
+
+
+The definition of an unaligned access
+=====================================
+
+Unaligned memory accesses occur when you try to read N bytes of data starting
+from an address that is not evenly divisible by N (i.e. addr % N != 0).
+For example, reading 4 bytes of data from address 0x10004 is fine, but
+reading 4 bytes of data from address 0x10005 would be an unaligned memory
+access.
+
+The above may seem a little vague, as memory access can happen in different
+ways. The context here is at the machine code level: certain instructions read
+or write a number of bytes to or from memory (e.g. movb, movw, movl in x86
+assembly). As will become clear, it is relatively easy to spot C statements
+which will compile to multiple-byte memory access instructions, namely when
+dealing with types such as u16, u32 and u64.
+
+
+Natural alignment
+=================
+
+The rule mentioned above forms what we refer to as natural alignment:
+When accessing N bytes of memory, the base memory address must be evenly
+divisible by N, i.e. addr % N == 0.
+
+When writing code, assume the target architecture has natural alignment
+requirements.
+
+In reality, only a few architectures require natural alignment on all sizes
+of memory access. However, we must consider ALL supported architectures;
+writing code that satisfies natural alignment requirements is the easiest way
+to achieve full portability.
+
+
+Why unaligned access is bad
+===========================
+
+The effects of performing an unaligned memory access vary from architecture
+to architecture. It would be easy to write a whole document on the differences
+here; a summary of the common scenarios is presented below:
+
+ - Some architectures are able to perform unaligned memory accesses
+   transparently, but there is usually a significant performance cost.
+ - Some architectures raise processor exceptions when unaligned accesses
+   happen. The exception handler is able to correct the unaligned access,
+   at significant cost to performance.
+ - Some architectures raise processor exceptions when unaligned accesses
+   happen, but the exceptions do not contain enough information for the
+   unaligned access to be corrected.
+ - Some architectures are not capable of unaligned memory access, but will
+   silently perform a different memory access to the one that was requested,
+   resulting a a subtle code bug that is hard to detect!
+
+It should be obvious from the above that if your code causes unaligned
+memory accesses to happen, your code will not work correctly on certain
+platforms and will cause performance problems on others.
+
+
+Code that does not cause unaligned access
+=========================================
+
+At first, the concepts above may seem a little hard to relate to actual
+coding practice. After all, you don't have a great deal of control over
+memory addresses of certain variables, etc.
+
+Fortunately things are not too complex, as in most cases, the compiler
+ensures that things will work for you. For example, take the following
+structure:
+
+       struct foo {
+               u16 field1;
+               u32 field2;
+               u8 field3;
+       };
+
+Let us assume that an instance of the above structure resides in memory
+starting at address 0x10000. With a basic level of understanding, it would
+not be unreasonable to expect that accessing field2 would cause an unaligned
+access. You'd be expecting field2 to be located at offset 2 bytes into the
+structure, i.e. address 0x10002, but that address is not evenly divisible
+by 4 (remember, we're reading a 4 byte value here).
+
+Fortunately, the compiler understands the alignment constraints, so in the
+above case it would insert 2 bytes of padding in between field1 and field2.
+Therefore, for standard structure types you can always rely on the compiler
+to pad structures so that accesses to fields are suitably aligned (assuming
+you do not cast the field to a type of different length).
+
+Similarly, you can also rely on the compiler to align variables and function
+parameters to a naturally aligned scheme, based on the size of the type of
+the variable.
+
+At this point, it should be clear that accessing a single byte (u8 or char)
+will never cause an unaligned access, because all memory addresses are evenly
+divisible by one.
+
+On a related topic, with the above considerations in mind you may observe
+that you could reorder the fields in the structure in order to place fields
+where padding would otherwise be inserted, and hence reduce the overall
+resident memory size of structure instances. The optimal layout of the
+above example is:
+
+       struct foo {
+               u32 field2;
+               u16 field1;
+               u8 field3;
+       };
+
+For a natural alignment scheme, the compiler would only have to add a single
+byte of padding at the end of the structure. This padding is added in order
+to satisfy alignment constraints for arrays of these structures.
+
+Another point worth mentioning is the use of __attribute__((packed)) on a
+structure type. This GCC-specific attribute tells the compiler never to
+insert any padding within structures, useful when you want to use a C struct
+to represent some data that comes in a fixed arrangement 'off the wire'.
+
+You might be inclined to believe that usage of this attribute can easily
+lead to unaligned accesses when accessing fields that do not satisfy
+architectural alignment requirements. However, again, the compiler is aware
+of the alignment constraints and will generate extra instructions to perform
+the memory access in a way that does not cause unaligned access. Of course,
+the extra instructions obviously cause a loss in performance compared to the
+non-packed case, so the packed attribute should only be used when avoiding
+structure padding is of importance.
+
+
+Code that causes unaligned access
+=================================
+
+With the above in mind, let's move onto a real life example of a function
+that can cause an unaligned memory access. The following function adapted
+from include/linux/etherdevice.h is an optimized routine to compare two
+ethernet MAC addresses for equality.
+
+unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2)
+{
+       const u16 *a = (const u16 *) addr1;
+       const u16 *b = (const u16 *) addr2;
+       return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
+}
+
+In the above function, the reference to a[0] causes 2 bytes (16 bits) to
+be read from memory starting at address addr1. Think about what would happen
+if addr1 was an odd address such as 0x10003. (Hint: it'd be an unaligned
+access.)
+
+Despite the potential unaligned access problems with the above function, it
+is included in the kernel anyway but is understood to only work on
+16-bit-aligned addresses. It is up to the caller to ensure this alignment or
+not use this function at all. This alignment-unsafe function is still useful
+as it is a decent optimization for the cases when you can ensure alignment,
+which is true almost all of the time in ethernet networking context.
+
+
+Here is another example of some code that could cause unaligned accesses:
+       void myfunc(u8 *data, u32 value)
+       {
+               [...]
+               *((u32 *) data) = cpu_to_le32(value);
+               [...]
+       }
+
+This code will cause unaligned accesses every time the data parameter points
+to an address that is not evenly divisible by 4.
+
+In summary, the 2 main scenarios where you may run into unaligned access
+problems involve:
+ 1. Casting variables to types of different lengths
+ 2. Pointer arithmetic followed by access to at least 2 bytes of data
+
+
+Avoiding unaligned accesses
+===========================
+
+The easiest way to avoid unaligned access is to use the get_unaligned() and
+put_unaligned() macros provided by the <asm/unaligned.h> header file.
+
+Going back to an earlier example of code that potentially causes unaligned
+access:
+
+       void myfunc(u8 *data, u32 value)
+       {
+               [...]
+               *((u32 *) data) = cpu_to_le32(value);
+               [...]
+       }
+
+To avoid the unaligned memory access, you would rewrite it as follows:
+
+       void myfunc(u8 *data, u32 value)
+       {
+               [...]
+               value = cpu_to_le32(value);
+               put_unaligned(value, (u32 *) data);
+               [...]
+       }
+
+The get_unaligned() macro works similarly. Assuming 'data' is a pointer to
+memory and you wish to avoid unaligned access, its usage is as follows:
+
+       u32 value = get_unaligned((u32 *) data);
+
+These macros work work for memory accesses of any length (not just 32 bits as
+in the examples above). Be aware that when compared to standard access of
+aligned memory, using these macros to access unaligned memory can be costly in
+terms of performance.
+
+If use of such macros is not convenient, another option is to use memcpy(),
+where the source or destination (or both) are of type u8* or unsigned char*.
+Due to the byte-wise nature of this operation, unaligned accesses are avoided.
+
+--
+Author: Daniel Drake <dsd@gentoo.org>
+With help from: Alan Cox, Avuton Olrich, Heikki Orsila, Jan Engelhardt,
+Johannes Berg, Kyle McMartin, Kyle Moffett, Randy Dunlap, Robert Hancock,
+Uli Kunitz, Vadim Lobanov
+
index 752613c..7b0ceaa 100644 (file)
@@ -4,3 +4,5 @@ ds2482
        - The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses.
 ds2490
        - The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges.
+w1-gpio
+       - GPIO 1-wire bus master driver.
diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio
new file mode 100644 (file)
index 0000000..af5d3b4
--- /dev/null
@@ -0,0 +1,33 @@
+Kernel driver w1-gpio
+=====================
+
+Author: Ville Syrjala <syrjala@sci.fi>
+
+
+Description
+-----------
+
+GPIO 1-wire bus master driver. The driver uses the GPIO API to control the
+wire and the GPIO pin can be specified using platform data.
+
+
+Example (mach-at91)
+-------------------
+
+#include <linux/w1-gpio.h>
+
+static struct w1_gpio_platform_data foo_w1_gpio_pdata = {
+       .pin            = AT91_PIN_PB20,
+       .is_open_drain  = 1,
+};
+
+static struct platform_device foo_w1_device = {
+       .name                   = "w1-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &foo_w1_gpio_pdata,
+};
+
+...
+       at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1);
+       at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1);
+       platform_device_register(&foo_w1_device);
index cffe13d..0885aa2 100644 (file)
@@ -338,13 +338,12 @@ S:        Maintained for 2.4; PCI support for 2.6.
 AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
 P:     Thomas Dahlmann
 M:     thomas.dahlmann@amd.com
-L:     info-linux@geode.amd.com
+L:     info-linux@geode.amd.com        (subscribers-only)
 S:     Supported
 
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
 P:     Jordan Crouse
-M:     info-linux@geode.amd.com
-L:     info-linux@geode.amd.com
+L:     info-linux@geode.amd.com        (subscribers-only)
 W:     http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
 S:     Supported
 
@@ -841,6 +840,12 @@ L: linux-kernel@vger.kernel.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
 S:     Maintained
 
+BLOCK2MTD DRIVER
+P:     Joern Engel
+M:     joern@lazybastard.org
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+
 BLUETOOTH SUBSYSTEM
 P:     Marcel Holtmann
 M:     marcel@holtmann.org
@@ -3031,8 +3036,8 @@ L:        linux-abi-devel@lists.sourceforge.net
 S:     Maintained
 
 PHRAM MTD DRIVER
-P:     Jörn Engel
-M:     joern@wh.fh-wedel.de
+P:     Joern Engel
+M:     joern@lazybastard.org
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
 
@@ -3862,6 +3867,12 @@ M:       oliver@neukum.name
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 
+USB AUERSWALD DRIVER
+P:     Wolfgang Muees
+M:     wolfgang@iksw-muees.de
+L:      linux-usb@vger.kernel.org
+S:     Maintained
+
 USB BLOCK DRIVER (UB ub)
 P:     Pete Zaitcev
 M:     zaitcev@redhat.com
@@ -4012,12 +4023,6 @@ S:       Maintained
 W:     http://geocities.com/i0xox0i
 W:     http://firstlight.net/cvs
 
-USB AUERSWALD DRIVER
-P:     Wolfgang Muees
-M:     wolfgang@iksw-muees.de
-L:      linux-usb@vger.kernel.org
-S:     Maintained
-
 USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
 P:     Gary Brubaker
 M:     xavyer@ix.netcom.com
index f45f28c..3f6265f 100644 (file)
@@ -7,15 +7,6 @@ config EARLY_PRINTK
        depends on ALPHA_GENERIC || ALPHA_SRM
        default y
 
-config DEBUG_RWLOCK
-       bool "Read-write spinlock debugging"
-       depends on DEBUG_KERNEL
-       help
-         If you say Y here then read-write lock processing will count how many
-         times it has tried to get the lock and issue an error message after
-         too many attempts.  If you suspect a rwlock problem or a kernel
-         hacker asks for this option then say Y.  Otherwise say N.
-
 config ALPHA_LEGACY_START_ADDRESS
        bool "Legacy kernel start address"
        depends on ALPHA_GENERIC
index 6da9c3d..e43f68f 100644 (file)
@@ -882,7 +882,6 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_SPINLOCK is not set
 CONFIG_DEBUG_INFO=y
 CONFIG_EARLY_PRINTK=y
-# CONFIG_DEBUG_RWLOCK is not set
 # CONFIG_DEBUG_SEMAPHORE is not set
 CONFIG_ALPHA_LEGACY_START_ADDRESS=y
 CONFIG_MATHEMU=y
index 6413c5f..72f9a61 100644 (file)
@@ -430,7 +430,7 @@ sys_getpagesize(void)
 asmlinkage unsigned long
 sys_getdtablesize(void)
 {
-       return NR_OPEN;
+       return sysctl_nr_open;
 }
 
 /*
index f4ab233..63c2073 100644 (file)
@@ -77,10 +77,6 @@ int smp_num_probed;          /* Internal processor count */
 int smp_num_cpus = 1;          /* Number that came online.  */
 EXPORT_SYMBOL(smp_num_cpus);
 
-extern void calibrate_delay(void);
-
-\f
-
 /*
  * Called by both boot and secondaries to move global data into
  *  per-processor storage.
index aa29ea5..0ce38df 100644 (file)
@@ -383,6 +383,7 @@ static void at91_lcdc_tft_power_control(int on)
 }
 
 static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+       .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
        .default_lcdcon2                = AT91SAM9261_DEFAULT_TFT_LCDCON2,
index f09347a..38313ab 100644 (file)
@@ -253,6 +253,7 @@ static void at91_lcdc_power_control(int on)
 
 /* Driver datas */
 static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+       .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
        .default_lcdcon2                = AT91SAM9263_DEFAULT_LCDCON2,
index a454451..eca558c 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/serial_8250.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 
 #include <asm/elf.h>
 #include <asm/io.h>
index b3bc0b5..9aa8800 100644 (file)
 
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/timex.h>
 #include <linux/param.h>
 #include <linux/types.h>
+#include <linux/init.h>
 
 #include <asm/processor.h>
 #include <asm/sysreg.h>
 
-int read_current_timer(unsigned long *timer_value)
+int __devinit read_current_timer(unsigned long *timer_value)
 {
        *timer_value = sysreg_read(COUNT);
        return 0;
index f8c411a..1795aab 100644 (file)
@@ -37,7 +37,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
index a72c7a6..97378b0 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 
 #include <asm/dma.h>
index 21df2f3..886f260 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index c37dd45..4026c2f 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index ac52b04..0185350 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index 8703b67..f7c1f96 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index 3e52f3f..8a3397d 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
index b8bbba8..d71e0be 100644 (file)
@@ -10,7 +10,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb_isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb_sl811.h>
index 7725415..119e6ea 100644 (file)
@@ -38,7 +38,7 @@
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
 #include <linux/usb/isp1362.h>
 #endif
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
index 3a79a90..bf9e738 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/usb/isp1362.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
index 7601c3b..ed863ce 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/spi/spi.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
index a74c087..b38ae1f 100644 (file)
@@ -708,7 +708,7 @@ static void __init reserve_dma_coherent(void)
 /*
  * calibrate the delay loop
  */
-void __init calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        loops_per_jiffy = __delay_loops_MHz * (1000000 / HZ);
 
index 8dec4dd..5a1b4cf 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/random.h>
 #include <linux/bootmem.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 #include <asm/traps.h>
index 480b1a5..32ee597 100644 (file)
@@ -120,7 +120,6 @@ static volatile unsigned long go[SLAVE + 1];
 
 #define DEBUG_ITC_SYNC 0
 
-extern void __devinit calibrate_delay (void);
 extern void start_ap (void);
 extern unsigned long ia64_iobase;
 
@@ -477,7 +476,7 @@ start_secondary (void *unused)
        return 0;
 }
 
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
 {
        return NULL;
 }
index ab3eaf8..2c676cc 100644 (file)
@@ -100,11 +100,11 @@ u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus)
 static irqreturn_t
 pcibr_error_intr_handler(int irq, void *arg)
 {
-       struct pcibus_info *soft = (struct pcibus_info *)arg;
+       struct pcibus_info *soft = arg;
 
-       if (sal_pcibr_error_interrupt(soft) < 0) {
+       if (sal_pcibr_error_interrupt(soft) < 0)
                panic("pcibr_error_intr_handler(): Fatal Bridge Error");
-       }
+
        return IRQ_HANDLED;
 }
 
index d10726f..cbe3653 100644 (file)
@@ -32,12 +32,10 @@ void __init amiga_chip_init(void)
     if (!AMIGAHW_PRESENT(CHIP_RAM))
        return;
 
-#ifndef CONFIG_APUS_FAST_EXCEPT
     /*
      *  Remove the first 4 pages where PPC exception handlers will be located
      */
     amiga_chip_size -= 0x4000;
-#endif
     chipram_res.end = amiga_chip_size-1;
     request_resource(&iomem_resource, &chipram_res);
 
index c4a4ffd..343fab4 100644 (file)
@@ -84,7 +84,7 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
 
 static irqreturn_t cia_handler(int irq, void *dev_id)
 {
-       struct ciabase *base = (struct ciabase *)dev_id;
+       struct ciabase *base = dev_id;
        int mach_irq;
        unsigned char ints;
 
index 0d55775..b50dbca 100644 (file)
@@ -1,6 +1,5 @@
 
 #include <linux/types.h>
-#include <linux/autoconf.h>
 
 void * memcpy(void * to, const void * from, size_t n)
 {
index 8527856..0b658f1 100644 (file)
@@ -27,7 +27,6 @@
  *     others have a second one : GPIO2
  */
 
-#include <linux/autoconf.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/types.h>
index 1e5dfc2..9d41dab 100644 (file)
@@ -52,7 +52,6 @@ int __cpu_logical_map[NR_CPUS];               /* Map logical to physical */
 EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(cpu_online_map);
 
-extern void __init calibrate_delay(void);
 extern void cpu_idle(void);
 
 /* Number of TCs (or siblings in Intel speak) per CPU core */
index 4c477c7..22fd41e 100644 (file)
@@ -356,7 +356,7 @@ asmlinkage int irix_syssgi(struct pt_regs *regs)
                        retval = NGROUPS_MAX;
                        goto out;
                case 5:
-                       retval = NR_OPEN;
+                       retval = sysctl_nr_open;
                        goto out;
                case 6:
                        retval = 1;
index 9166bd1..bc989e5 100644 (file)
@@ -2,15 +2,6 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config DEBUG_RWLOCK
-        bool "Read-write spinlock debugging"
-        depends on DEBUG_KERNEL && SMP
-        help
-          If you say Y here then read-write lock processing will count how many
-          times it has tried to get the lock and issue an error message after
-          too many attempts.  If you suspect a rwlock problem or a kernel
-          hacker asks for this option then say Y.  Otherwise say N.
-
 config DEBUG_RODATA
        bool "Write protect kernel read-only data structures"
        depends on DEBUG_KERNEL
index ea07121..ddacc72 100644 (file)
@@ -1050,7 +1050,6 @@ CONFIG_SCHED_DEBUG=y
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_DEBUG_RWLOCK is not set
 # CONFIG_DEBUG_RODATA is not set
 
 #
index 5cd3db5..3b26fbd 100644 (file)
@@ -66,6 +66,7 @@
 #include <asm/smp.h>
 #include <asm/vdso_datapage.h>
 #include <asm/firmware.h>
+#include <asm/cputime.h>
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iseries/it_lp_queue.h>
 #include <asm/iseries/hv_call_xm.h>
@@ -189,6 +190,8 @@ u64 __cputime_sec_factor;
 EXPORT_SYMBOL(__cputime_sec_factor);
 u64 __cputime_clockt_factor;
 EXPORT_SYMBOL(__cputime_clockt_factor);
+DEFINE_PER_CPU(unsigned long, cputime_last_delta);
+DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta);
 
 static void calc_cputime_factors(void)
 {
@@ -257,8 +260,8 @@ void account_system_vtime(struct task_struct *tsk)
        }
        account_system_time(tsk, 0, delta);
        account_system_time_scaled(tsk, deltascaled);
-       get_paca()->purrdelta = delta;
-       get_paca()->spurrdelta = deltascaled;
+       per_cpu(cputime_last_delta, smp_processor_id()) = delta;
+       per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled;
        local_irq_restore(flags);
 }
 
@@ -276,10 +279,7 @@ void account_process_tick(struct task_struct *tsk, int user_tick)
        get_paca()->user_time = 0;
        account_user_time(tsk, utime);
 
-       /* Estimate the scaled utime by scaling the real utime based
-        * on the last spurr to purr ratio */
-       utimescaled = utime * get_paca()->spurrdelta / get_paca()->purrdelta;
-       get_paca()->spurrdelta = get_paca()->purrdelta = 0;
+       utimescaled = cputime_to_scaled(utime);
        account_user_time_scaled(tsk, utimescaled);
 }
 
index c04abcc..792d3ce 100644 (file)
@@ -113,8 +113,6 @@ static inline void debug_calc_bogomips(void)
         * result. We backup/restore the value to avoid affecting the
         * core cpufreq framework's own calculation.
         */
-       extern void calibrate_delay(void);
-
        unsigned long save_lpj = loops_per_jiffy;
        calibrate_delay();
        loops_per_jiffy = save_lpj;
index 25ef55b..ec1defe 100644 (file)
@@ -418,7 +418,7 @@ scc_enet_rx(struct net_device *dev)
        struct  sk_buff *skb;
        ushort  pkt_len;
 
-       cep = (struct scc_enet_private *)dev->priv;
+       cep = dev->priv;
 
        /* First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
index a3a27da..bcc3aa9 100644 (file)
@@ -682,7 +682,7 @@ fcc_enet_rx(struct net_device *dev)
        struct  sk_buff *skb;
        ushort  pkt_len;
 
-       cep = (struct fcc_enet_private *)dev->priv;
+       cep = dev->priv;
 
        /* First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
index 52b64fc..8a24bc4 100644 (file)
@@ -143,11 +143,6 @@ SECTIONS
 
   . = ALIGN(4096);
   __init_end = .;
-
-  . = ALIGN(4096);
-  _sextratext = .;
-  _eextratext = .;
-
   __bss_start = .;
   .bss       :
   {
index 3c56654..3844985 100644 (file)
@@ -91,20 +91,11 @@ extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi
 #define cached_21      (((char *)(ppc_cached_irq_mask))[3])
 #define cached_A1      (((char *)(ppc_cached_irq_mask))[2])
 
-#ifdef CONFIG_SOUND_CS4232
-long ppc_cs4232_dma, ppc_cs4232_dma2;
-#endif
-
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
 
-#ifdef CONFIG_SOUND_CS4232
-EXPORT_SYMBOL(ppc_cs4232_dma);
-EXPORT_SYMBOL(ppc_cs4232_dma2);
-#endif
-
 /* useful ISA ports */
 #define PREP_SYSCTL    0x81c
 /* present in the IBM reference design; possibly identical in Mot boxes: */
@@ -569,74 +560,6 @@ prep_show_percpuinfo(struct seq_file *m, int i)
        return 0;
 }
 
-#ifdef CONFIG_SOUND_CS4232
-static long __init masktoint(unsigned int i)
-{
-       int t = -1;
-       while (i >> ++t)
-               ;
-       return (t-1);
-}
-
-/*
- * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h
- * to distinguish sound dma-channels from others. This is because
- * blocksize on 16 bit dma-channels 5,6,7 is 128k, but
- * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3
- */
-
-static void __init prep_init_sound(void)
-{
-       PPC_DEVICE *audiodevice = NULL;
-
-       /*
-        * Get the needed resource information from residual data.
-        *
-        */
-       if (have_residual_data)
-               audiodevice = residual_find_device(~0, NULL,
-                               MultimediaController, AudioController, -1, 0);
-
-       if (audiodevice != NULL) {
-               PnP_TAG_PACKET *pkt;
-
-               pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
-                               S5_Packet, 0);
-               if (pkt != NULL)
-                       ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask);
-               pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
-                               S5_Packet, 1);
-               if (pkt != NULL)
-                       ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask);
-       }
-
-       /*
-        * These are the PReP specs' defaults for the cs4231.  We use these
-        * as fallback incase we don't have residual data.
-        * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7
-        * will use the other values.
-        */
-       if (audiodevice == NULL) {
-               switch (_prep_type) {
-               case _PREP_IBM:
-                       ppc_cs4232_dma = 1;
-                       ppc_cs4232_dma2 = -1;
-                       break;
-               default:
-                       ppc_cs4232_dma = 6;
-                       ppc_cs4232_dma2 = 7;
-               }
-       }
-
-       /*
-        * Find a way to push this information to the cs4232 driver
-        * Give it out with printk, when not in cmd_line?
-        * Append it to cmd_line and boot_command_line?
-        * Format is cs4232=io,irq,dma,dma2
-        */
-}
-#endif /* CONFIG_SOUND_CS4232 */
-
 /*
  * Fill out screen_info according to the residual data. This allows us to use
  * at least vesafb.
@@ -898,10 +821,6 @@ prep_setup_arch(void)
                }
        }
 
-#ifdef CONFIG_SOUND_CS4232
-       prep_init_sound();
-#endif /* CONFIG_SOUND_CS4232 */
-
        prep_init_vesa();
 
        switch (_prep_type) {
index eda7176..2b708ec 100644 (file)
@@ -14,7 +14,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/pm.h>
 #include <linux/mm.h>
 #include <asm/machvec.h>
index 9c830fd..c74440d 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/machvec.h>
 #include <asm/addrspace.h>
 #include <asm/lboxre2.h>
index a43b477..f7a8d5c 100644 (file)
@@ -15,7 +15,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/types.h>
 #include <net/ax88796.h>
 #include <asm/machvec.h>
index 3452b07..a0ef81b 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/serial_8250.h>
 #include <linux/sm501.h>
 #include <linux/sm501-regs.h>
index 5df32f2..acc5932 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/machvec.h>
 #include <asm/sdk7780.h>
 #include <asm/heartbeat.h>
index eb97dca..b1a3d9d 100644 (file)
@@ -12,7 +12,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <asm/machvec.h>
 #include <asm/se7722.h>
 #include <asm/io.h>
index 89a6de9..0def481 100644 (file)
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/profile.h>
+#include <linux/delay.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 #include <asm/irq_regs.h>
 
-#include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -41,8 +41,6 @@
 
 extern ctxd_t *srmmu_ctx_table_phys;
 
-extern void calibrate_delay(void);
-
 static volatile int smp_processors_ready = 0;
 static int smp_highest_cpu;
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
index 730eb57..0b94072 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/profile.h>
+#include <linux/delay.h>
+
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/irq_regs.h>
@@ -23,7 +25,6 @@
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 
-#include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -39,8 +40,6 @@
 
 extern ctxd_t *srmmu_ctx_table_phys;
 
-extern void calibrate_delay(void);
-
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
 extern unsigned char boot_cpu_id;
 
index ee010f4..9064485 100644 (file)
@@ -79,7 +79,8 @@ sys_call_table:
 /*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .long sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
+/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
+/*315*/        .long sys_timerfd_settime, sys_timerfd_gettime
 
 #ifdef CONFIG_SUNOS_EMUL
        /* Now the SunOS syscall table. */
@@ -197,6 +198,7 @@ sunos_sys_table:
        .long sunos_nosys, sunos_nosys, sunos_nosys
        .long sunos_nosys
 /*310*/        .long sunos_nosys, sunos_nosys, sunos_nosys
-       .long sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys
 
 #endif
index f62d9f6..833d74b 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24-rc4
-# Tue Dec  4 00:37:59 2007
+# Linux kernel version: 2.6.24
+# Tue Feb  5 17:28:19 2008
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -17,6 +17,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_AUDIT_ARCH=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_OF=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
@@ -30,13 +31,15 @@ CONFIG_HZ_100=y
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_HOTPLUG_CPU=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
 # General setup
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
@@ -76,6 +79,7 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -83,6 +87,14 @@ CONFIG_SLUB_DEBUG=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=m
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
@@ -92,6 +104,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
 CONFIG_BLK_DEV_IO_TRACE=y
 CONFIG_BLK_DEV_BSG=y
@@ -109,6 +122,8 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_RCU is not set
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_GENERIC_HARDIRQS=y
 
@@ -119,7 +134,8 @@ CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_SMP is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=64
 # CONFIG_CPU_FREQ is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
@@ -169,9 +185,12 @@ CONFIG_BINFMT_ELF32=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 CONFIG_SOLARIS_EMUL=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
+# CONFIG_RCU_TRACE is not set
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -189,6 +208,7 @@ CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 # CONFIG_XFRM_SUB_POLICY is not set
 CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
 CONFIG_NET_KEY=m
 CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
@@ -249,9 +269,9 @@ CONFIG_IP_DCCP_ACKVEC=y
 CONFIG_IP_DCCP_CCID2=m
 # CONFIG_IP_DCCP_CCID2_DEBUG is not set
 CONFIG_IP_DCCP_CCID3=m
-CONFIG_IP_DCCP_TFRC_LIB=m
 # CONFIG_IP_DCCP_CCID3_DEBUG is not set
 CONFIG_IP_DCCP_CCID3_RTO=100
+CONFIG_IP_DCCP_TFRC_LIB=m
 
 #
 # DCCP Kernel Hacking
@@ -279,6 +299,7 @@ CONFIG_VLAN_8021Q=m
 CONFIG_NET_PKTGEN=m
 CONFIG_NET_TCPPROBE=m
 # CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
@@ -343,6 +364,7 @@ CONFIG_BLK_DEV_IDE=y
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
@@ -359,7 +381,6 @@ CONFIG_IDE_GENERIC=y
 # PCI IDE chipsets support
 #
 CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
@@ -389,7 +410,6 @@ CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_TC86C001 is not set
-# CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_IDE_ARCH_OBSOLETE_INIT=y
 # CONFIG_BLK_DEV_HD is not set
@@ -501,7 +521,6 @@ CONFIG_NETDEVICES=y
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_IP1000 is not set
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
@@ -533,6 +552,7 @@ CONFIG_NET_PCI=y
 # CONFIG_NE2K_PCI is not set
 # CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -545,6 +565,9 @@ CONFIG_E1000=m
 CONFIG_E1000_NAPI=y
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
 # CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
@@ -570,6 +593,7 @@ CONFIG_NETDEV_10000=y
 CONFIG_NIU=m
 # CONFIG_MLX4_CORE is not set
 # CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
 # CONFIG_TR is not set
 
 #
@@ -602,7 +626,6 @@ CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 CONFIG_SLHC=m
 # CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
@@ -679,6 +702,7 @@ CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
 # CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
 
 #
 # Serial drivers
@@ -747,13 +771,13 @@ CONFIG_I2C_ALGOBIT=y
 #
 # Miscellaneous I2C Chip support
 #
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
 # CONFIG_DS1682 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_TPS65010 is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
@@ -990,6 +1014,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_BT87X is not set
 # CONFIG_SND_CA0106 is not set
 # CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
 # CONFIG_SND_DARLA20 is not set
@@ -1014,6 +1039,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_HDA_INTEL is not set
 # CONFIG_SND_HDSP is not set
 # CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
@@ -1031,6 +1057,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
 # CONFIG_SND_VX222 is not set
 # CONFIG_SND_YMFPCI is not set
 # CONFIG_SND_AC97_POWER_SAVE is not set
@@ -1057,6 +1084,10 @@ CONFIG_SND_SUN_CS4231=m
 # SoC Audio support for SuperH
 #
 
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
 #
 # Open Sound System
 #
@@ -1080,6 +1111,7 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
 
 #
 # Miscellaneous USB options
@@ -1093,7 +1125,6 @@ CONFIG_USB_DEVICEFS=y
 # USB Host Controller Drivers
 #
 CONFIG_USB_EHCI_HCD=m
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_ISP116X_HCD is not set
@@ -1143,10 +1174,6 @@ CONFIG_USB_STORAGE=m
 #
 # USB port drivers
 #
-
-#
-# USB Serial Converter support
-#
 # CONFIG_USB_SERIAL is not set
 
 #
@@ -1172,14 +1199,6 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
-#
-# USB Gadget Support
-#
 # CONFIG_USB_GADGET is not set
 # CONFIG_MMC is not set
 # CONFIG_NEW_LEDS is not set
@@ -1332,11 +1351,6 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 # CONFIG_DLM is not set
-CONFIG_INSTRUMENTATION=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_KPROBES=y
-# CONFIG_MARKERS is not set
 
 #
 # Kernel hacking
@@ -1374,6 +1388,8 @@ CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_FORCED_INLINING=y
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_SAMPLES is not set
@@ -1396,8 +1412,9 @@ CONFIG_ASYNC_MEMCPY=m
 CONFIG_ASYNC_XOR=m
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD=y
 CONFIG_CRYPTO_BLKCIPHER=y
+# CONFIG_CRYPTO_SEQIV is not set
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
@@ -1416,6 +1433,9 @@ CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_XTS=m
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_CCM is not set
 # CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_FCRYPT=m
@@ -1431,13 +1451,16 @@ CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_KHAZAD=m
 CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_SEED=m
+# CONFIG_CRYPTO_SALSA20 is not set
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
 CONFIG_CRYPTO_CAMELLIA=m
 CONFIG_CRYPTO_TEST=m
 CONFIG_CRYPTO_AUTHENC=m
+# CONFIG_CRYPTO_LZO is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
 
 #
 # Library routines
index ef50d21..4b78b24 100644 (file)
@@ -11,7 +11,7 @@ obj-y         := process.o setup.o cpu.o idprom.o \
                   traps.o auxio.o una_asm.o sysfs.o iommu.o \
                   irq.o ptrace.o time.o sys_sparc.o signal.o \
                   unaligned.o central.o pci.o starfire.o semaphore.o \
-                  power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
+                  power.o sbus.o sparc64_ksyms.o chmc.o \
                   visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
 
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
index 4b9115a..5623a4d 100644 (file)
@@ -472,94 +472,15 @@ static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
-
-static void fill_sg(iopte_t *iopte, struct scatterlist *sg,
-                   int nused, int nelems,
-                   unsigned long iopte_protection)
-{
-       struct scatterlist *dma_sg = sg;
-       int i;
-
-       for (i = 0; i < nused; i++) {
-               unsigned long pteval = ~0UL;
-               u32 dma_npages;
-
-               dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
-                             dma_sg->dma_length +
-                             ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
-               do {
-                       unsigned long offset;
-                       signed int len;
-
-                       /* If we are here, we know we have at least one
-                        * more page to map.  So walk forward until we
-                        * hit a page crossing, and begin creating new
-                        * mappings from that spot.
-                        */
-                       for (;;) {
-                               unsigned long tmp;
-
-                               tmp = SG_ENT_PHYS_ADDRESS(sg);
-                               len = sg->length;
-                               if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = tmp & IO_PAGE_MASK;
-                                       offset = tmp & (IO_PAGE_SIZE - 1UL);
-                                       break;
-                               }
-                               if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
-                                       offset = 0UL;
-                                       len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
-                                       break;
-                               }
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-
-                       pteval = iopte_protection | (pteval & IOPTE_PAGE);
-                       while (len > 0) {
-                               *iopte++ = __iopte(pteval);
-                               pteval += IO_PAGE_SIZE;
-                               len -= (IO_PAGE_SIZE - offset);
-                               offset = 0;
-                               dma_npages--;
-                       }
-
-                       pteval = (pteval & IOPTE_PAGE) + len;
-                       sg = sg_next(sg);
-                       nelems--;
-
-                       /* Skip over any tail mappings we've fully mapped,
-                        * adjusting pteval along the way.  Stop when we
-                        * detect a page crossing event.
-                        */
-                       while (nelems &&
-                              (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
-                              (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
-                              ((pteval ^
-                                (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
-                               pteval += sg->length;
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-                       if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
-                               pteval = ~0UL;
-               } while (dma_npages != 0);
-               dma_sg = sg_next(dma_sg);
-       }
-}
-
 static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
                         int nelems, enum dma_data_direction direction)
 {
-       struct iommu *iommu;
+       unsigned long flags, ctx, i, npages, iopte_protection;
+       struct scatterlist *sg;
        struct strbuf *strbuf;
-       unsigned long flags, ctx, npages, iopte_protection;
+       struct iommu *iommu;
        iopte_t *base;
        u32 dma_base;
-       struct scatterlist *sgtmp;
-       int used;
 
        /* Fast path single entry scatterlists. */
        if (nelems == 1) {
@@ -578,11 +499,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        if (unlikely(direction == DMA_NONE))
                goto bad_no_ctx;
 
-       /* Step 1: Prepare scatter list. */
-
-       npages = prepare_sg(dev, sglist, nelems);
-
-       /* Step 2: Allocate a cluster and context, if necessary. */
+       npages = calc_npages(sglist, nelems);
 
        spin_lock_irqsave(&iommu->lock, flags);
 
@@ -599,18 +516,6 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        dma_base = iommu->page_table_map_base +
                ((base - iommu->page_table) << IO_PAGE_SHIFT);
 
-       /* Step 3: Normalize DMA addresses. */
-       used = nelems;
-
-       sgtmp = sglist;
-       while (used && sgtmp->dma_length) {
-               sgtmp->dma_address += dma_base;
-               sgtmp = sg_next(sgtmp);
-               used--;
-       }
-       used = nelems - used;
-
-       /* Step 4: Create the mappings. */
        if (strbuf->strbuf_enabled)
                iopte_protection = IOPTE_STREAMING(ctx);
        else
@@ -618,13 +523,27 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
        if (direction != DMA_TO_DEVICE)
                iopte_protection |= IOPTE_WRITE;
 
-       fill_sg(base, sglist, used, nelems, iopte_protection);
+       for_each_sg(sglist, sg, nelems, i) {
+               unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+               unsigned long slen = sg->length;
+               unsigned long this_npages;
 
-#ifdef VERIFY_SG
-       verify_sglist(sglist, nelems, base, npages);
-#endif
+               this_npages = iommu_num_pages(paddr, slen);
 
-       return used;
+               sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK);
+               sg->dma_length = slen;
+
+               paddr &= IO_PAGE_MASK;
+               while (this_npages--) {
+                       iopte_val(*base) = iopte_protection | paddr;
+
+                       base++;
+                       paddr += IO_PAGE_SIZE;
+                       dma_base += IO_PAGE_SIZE;
+               }
+       }
+
+       return nelems;
 
 bad:
        iommu_free_ctx(iommu, ctx);
@@ -637,11 +556,10 @@ bad_no_ctx:
 static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction)
 {
-       struct iommu *iommu;
+       unsigned long flags, ctx, i, npages;
        struct strbuf *strbuf;
+       struct iommu *iommu;
        iopte_t *base;
-       unsigned long flags, ctx, i, npages;
-       struct scatterlist *sg, *sgprv;
        u32 bus_addr;
 
        if (unlikely(direction == DMA_NONE)) {
@@ -654,15 +572,7 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
 
        bus_addr = sglist->dma_address & IO_PAGE_MASK;
 
-       sgprv = NULL;
-       for_each_sg(sglist, sg, nelems, i) {
-               if (sg->dma_length == 0)
-                       break;
-               sgprv = sg;
-       }
-
-       npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) -
-                 bus_addr) >> IO_PAGE_SHIFT;
+       npages = calc_npages(sglist, nelems);
 
        base = iommu->page_table +
                ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c
deleted file mode 100644 (file)
index 72a4acf..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 davem Exp $
- * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
- *
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#include <linux/dma-mapping.h>
-#include "iommu_common.h"
-
-/* You are _strongly_ advised to enable the following debugging code
- * any time you make changes to the sg code below, run it for a while
- * with filesystems mounted read-only before buying the farm... -DaveM
- */
-
-#ifdef VERIFY_SG
-static int verify_lengths(struct scatterlist *sglist, int nents, int npages)
-{
-       int sg_len, dma_len;
-       int i, pgcount;
-       struct scatterlist *sg;
-
-       sg_len = 0;
-       for_each_sg(sglist, sg, nents, i)
-               sg_len += sg->length;
-
-       dma_len = 0;
-       for_each_sg(sglist, sg, nents, i) {
-               if (!sg->dma_length)
-                       break;
-               dma_len += sg->dma_length;
-       }
-
-       if (sg_len != dma_len) {
-               printk("verify_lengths: Error, different, sg[%d] dma[%d]\n",
-                      sg_len, dma_len);
-               return -1;
-       }
-
-       pgcount = 0;
-       for_each_sg(sglist, sg, nents, i) {
-               unsigned long start, end;
-
-               if (!sg->dma_length)
-                       break;
-
-               start = sg->dma_address;
-               start = start & IO_PAGE_MASK;
-
-               end = sg->dma_address + sg->dma_length;
-               end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK;
-
-               pgcount += ((end - start) >> IO_PAGE_SHIFT);
-       }
-
-       if (pgcount != npages) {
-               printk("verify_lengths: Error, page count wrong, "
-                      "npages[%d] pgcount[%d]\n",
-                      npages, pgcount);
-               return -1;
-       }
-
-       /* This test passes... */
-       return 0;
-}
-
-static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
-{
-       struct scatterlist *sg = *__sg;
-       iopte_t *iopte = *__iopte;
-       u32 dlen = dma_sg->dma_length;
-       u32 daddr;
-       unsigned int sglen;
-       unsigned long sgaddr;
-
-       daddr = dma_sg->dma_address;
-       sglen = sg->length;
-       sgaddr = (unsigned long) sg_virt(sg);
-       while (dlen > 0) {
-               unsigned long paddr;
-
-               /* SG and DMA_SG must begin at the same sub-page boundary. */
-               if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) {
-                       printk("verify_one_map: Wrong start offset "
-                              "sg[%08lx] dma[%08x]\n",
-                              sgaddr, daddr);
-                       nents = -1;
-                       goto out;
-               }
-
-               /* Verify the IOPTE points to the right page. */
-               paddr = iopte_val(*iopte) & IOPTE_PAGE;
-               if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) {
-                       printk("verify_one_map: IOPTE[%08lx] maps the "
-                              "wrong page, should be [%08lx]\n",
-                              iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET);
-                       nents = -1;
-                       goto out;
-               }
-
-               /* If this SG crosses a page, adjust to that next page
-                * boundary and loop.
-                */
-               if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) {
-                       unsigned long next_page, diff;
-
-                       next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK;
-                       diff = next_page - sgaddr;
-                       sgaddr += diff;
-                       daddr += diff;
-                       sglen -= diff;
-                       dlen -= diff;
-                       if (dlen > 0)
-                               iopte++;
-                       continue;
-               }
-
-               /* SG wholly consumed within this page. */
-               daddr += sglen;
-               dlen -= sglen;
-
-               if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0))
-                       iopte++;
-
-               sg = sg_next(sg);
-               if (--nents <= 0)
-                       break;
-               sgaddr = (unsigned long) sg_virt(sg);
-               sglen = sg->length;
-       }
-       if (dlen < 0) {
-               /* Transfer overrun, big problems. */
-               printk("verify_one_map: Transfer overrun by %d bytes.\n",
-                      -dlen);
-               nents = -1;
-       } else {
-               /* Advance to next dma_sg implies that the next iopte will
-                * begin it.
-                */
-               iopte++;
-       }
-
-out:
-       *__sg = sg;
-       *__iopte = iopte;
-       return nents;
-}
-
-static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
-{
-       struct scatterlist *dma_sg = sg;
-       struct scatterlist *orig_dma_sg = dma_sg;
-       int orig_nents = nents;
-
-       for (;;) {
-               nents = verify_one_map(dma_sg, &sg, nents, &iopte);
-               if (nents <= 0)
-                       break;
-               dma_sg = sg_next(dma_sg);
-               if (dma_sg->dma_length == 0)
-                       break;
-       }
-
-       if (nents > 0) {
-               printk("verify_maps: dma maps consumed by some sgs remain (%d)\n",
-                      nents);
-               return -1;
-       }
-
-       if (nents < 0) {
-               printk("verify_maps: Error, messed up mappings, "
-                      "at sg %d dma_sg %d\n",
-                      (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg));
-               return -1;
-       }
-
-       /* This test passes... */
-       return 0;
-}
-
-void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int npages)
-{
-       struct scatterlist *sg;
-
-       if (verify_lengths(sglist, nents, npages) < 0 ||
-           verify_maps(sglist, nents, iopte) < 0) {
-               int i;
-
-               printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
-               printk("%016lx.\n", sglist->dma_address & IO_PAGE_MASK);
-
-               for_each_sg(sglist, sg, nents, i) {
-                       printk("sg(%d): page_addr(%p) off(%x) length(%x) "
-                              "dma_address[%016x] dma_length[%016x]\n",
-                              i,
-                              page_address(sg_page(sg)), sg->offset,
-                              sg->length,
-                              sg->dma_address, sg->dma_length);
-               }
-       }
-
-       /* Seems to be ok */
-}
-#endif
-
-unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents)
-{
-       struct scatterlist *dma_sg = sg;
-       unsigned long prev;
-       u32 dent_addr, dent_len;
-       unsigned int max_seg_size;
-
-       prev  = (unsigned long) sg_virt(sg);
-       prev += (unsigned long) (dent_len = sg->length);
-       dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL));
-       max_seg_size = dma_get_max_seg_size(dev);
-       while (--nents) {
-               unsigned long addr;
-
-               sg = sg_next(sg);
-               addr = (unsigned long) sg_virt(sg);
-               if (! VCONTIG(prev, addr) ||
-                       dent_len + sg->length > max_seg_size) {
-                       dma_sg->dma_address = dent_addr;
-                       dma_sg->dma_length = dent_len;
-                       dma_sg = sg_next(dma_sg);
-
-                       dent_addr = ((dent_addr +
-                                     dent_len +
-                                     (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT);
-                       dent_addr <<= IO_PAGE_SHIFT;
-                       dent_addr += addr & (IO_PAGE_SIZE - 1UL);
-                       dent_len = 0;
-               }
-               dent_len += sg->length;
-               prev = addr + sg->length;
-       }
-       dma_sg->dma_address = dent_addr;
-       dma_sg->dma_length = dent_len;
-
-       if (dma_sg != sg) {
-               dma_sg = sg_next(dma_sg);
-               dma_sg->dma_length = 0;
-       }
-
-       return ((unsigned long) dent_addr +
-               (unsigned long) dent_len +
-               (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
-}
index a90d046..4b5cafa 100644 (file)
  */
 #define IOMMU_PAGE_SHIFT               13
 
+#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
+
+static inline unsigned long iommu_num_pages(unsigned long vaddr,
+                                           unsigned long slen)
+{
+       unsigned long npages;
+
+       npages = IO_PAGE_ALIGN(vaddr + slen) - (vaddr & IO_PAGE_MASK);
+       npages >>= IO_PAGE_SHIFT;
+
+       return npages;
+}
+
+static inline unsigned long calc_npages(struct scatterlist *sglist, int nelems)
+{
+       unsigned long i, npages = 0;
+       struct scatterlist *sg;
+
+       for_each_sg(sglist, sg, nelems, i) {
+               unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+               npages += iommu_num_pages(paddr, sg->length);
+       }
+
+       return npages;
+}
+
 /* You are _strongly_ advised to enable the following debugging code
  * any time you make changes to the sg code below, run it for a while
  * with filesystems mounted read-only before buying the farm... -DaveM
index 5ea2eab..61baf8d 100644 (file)
@@ -365,113 +365,14 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-#define SG_ENT_PHYS_ADDRESS(SG)        (__pa(sg_virt((SG))))
-
-static long fill_sg(long entry, struct device *dev,
-                   struct scatterlist *sg,
-                   int nused, int nelems, unsigned long prot)
-{
-       struct scatterlist *dma_sg = sg;
-       unsigned long flags;
-       int i;
-
-       local_irq_save(flags);
-
-       iommu_batch_start(dev, prot, entry);
-
-       for (i = 0; i < nused; i++) {
-               unsigned long pteval = ~0UL;
-               u32 dma_npages;
-
-               dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
-                             dma_sg->dma_length +
-                             ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
-               do {
-                       unsigned long offset;
-                       signed int len;
-
-                       /* If we are here, we know we have at least one
-                        * more page to map.  So walk forward until we
-                        * hit a page crossing, and begin creating new
-                        * mappings from that spot.
-                        */
-                       for (;;) {
-                               unsigned long tmp;
-
-                               tmp = SG_ENT_PHYS_ADDRESS(sg);
-                               len = sg->length;
-                               if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = tmp & IO_PAGE_MASK;
-                                       offset = tmp & (IO_PAGE_SIZE - 1UL);
-                                       break;
-                               }
-                               if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
-                                       pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
-                                       offset = 0UL;
-                                       len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
-                                       break;
-                               }
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-
-                       pteval = (pteval & IOPTE_PAGE);
-                       while (len > 0) {
-                               long err;
-
-                               err = iommu_batch_add(pteval);
-                               if (unlikely(err < 0L))
-                                       goto iommu_map_failed;
-
-                               pteval += IO_PAGE_SIZE;
-                               len -= (IO_PAGE_SIZE - offset);
-                               offset = 0;
-                               dma_npages--;
-                       }
-
-                       pteval = (pteval & IOPTE_PAGE) + len;
-                       sg = sg_next(sg);
-                       nelems--;
-
-                       /* Skip over any tail mappings we've fully mapped,
-                        * adjusting pteval along the way.  Stop when we
-                        * detect a page crossing event.
-                        */
-                       while (nelems &&
-                              (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
-                              (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
-                              ((pteval ^
-                                (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
-                               pteval += sg->length;
-                               sg = sg_next(sg);
-                               nelems--;
-                       }
-                       if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
-                               pteval = ~0UL;
-               } while (dma_npages != 0);
-               dma_sg = sg_next(dma_sg);
-       }
-
-       if (unlikely(iommu_batch_end() < 0L))
-               goto iommu_map_failed;
-
-       local_irq_restore(flags);
-       return 0;
-
-iommu_map_failed:
-       local_irq_restore(flags);
-       return -1L;
-}
-
 static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
                         int nelems, enum dma_data_direction direction)
 {
+       unsigned long flags, npages, i, prot;
+       struct scatterlist *sg;
        struct iommu *iommu;
-       unsigned long flags, npages, prot;
-       u32 dma_base;
-       struct scatterlist *sgtmp;
        long entry, err;
-       int used;
+       u32 dma_base;
 
        /* Fast path single entry scatterlists. */
        if (nelems == 1) {
@@ -489,10 +390,8 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
        if (unlikely(direction == DMA_NONE))
                goto bad;
 
-       /* Step 1: Prepare scatter list. */
-       npages = prepare_sg(dev, sglist, nelems);
+       npages = calc_npages(sglist, nelems);
 
-       /* Step 2: Allocate a cluster and context, if necessary. */
        spin_lock_irqsave(&iommu->lock, flags);
        entry = arena_alloc(&iommu->arena, npages);
        spin_unlock_irqrestore(&iommu->lock, flags);
@@ -503,27 +402,45 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
        dma_base = iommu->page_table_map_base +
                (entry << IO_PAGE_SHIFT);
 
-       /* Step 3: Normalize DMA addresses. */
-       used = nelems;
-
-       sgtmp = sglist;
-       while (used && sgtmp->dma_length) {
-               sgtmp->dma_address += dma_base;
-               sgtmp = sg_next(sgtmp);
-               used--;
-       }
-       used = nelems - used;
-
-       /* Step 4: Create the mappings. */
        prot = HV_PCI_MAP_ATTR_READ;
        if (direction != DMA_TO_DEVICE)
                prot |= HV_PCI_MAP_ATTR_WRITE;
 
-       err = fill_sg(entry, dev, sglist, used, nelems, prot);
+       local_irq_save(flags);
+
+       iommu_batch_start(dev, prot, entry);
+
+       for_each_sg(sglist, sg, nelems, i) {
+               unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg);
+               unsigned long slen = sg->length;
+               unsigned long this_npages;
+
+               this_npages = iommu_num_pages(paddr, slen);
+
+               sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK);
+               sg->dma_length = slen;
+
+               paddr &= IO_PAGE_MASK;
+               while (this_npages--) {
+                       err = iommu_batch_add(paddr);
+                       if (unlikely(err < 0L)) {
+                               local_irq_restore(flags);
+                               goto iommu_map_failed;
+                       }
+
+                       paddr += IO_PAGE_SIZE;
+                       dma_base += IO_PAGE_SIZE;
+               }
+       }
+
+       err = iommu_batch_end();
+
+       local_irq_restore(flags);
+
        if (unlikely(err < 0L))
                goto iommu_map_failed;
 
-       return used;
+       return nelems;
 
 bad:
        if (printk_ratelimit())
@@ -541,12 +458,11 @@ iommu_map_failed:
 static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction)
 {
+       unsigned long flags, npages;
        struct pci_pbm_info *pbm;
+       u32 devhandle, bus_addr;
        struct iommu *iommu;
-       unsigned long flags, i, npages;
-       struct scatterlist *sg, *sgprv;
        long entry;
-       u32 devhandle, bus_addr;
 
        if (unlikely(direction == DMA_NONE)) {
                if (printk_ratelimit())
@@ -558,16 +474,8 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
        devhandle = pbm->devhandle;
        
        bus_addr = sglist->dma_address & IO_PAGE_MASK;
-       sgprv = NULL;
-       for_each_sg(sglist, sg, nelems, i) {
-               if (sg->dma_length == 0)
-                       break;
-
-               sgprv = sg;
-       }
 
-       npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) -
-                 bus_addr) >> IO_PAGE_SHIFT;
+       npages = calc_npages(sglist, nelems);
 
        entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
index c399449..a8052b7 100644 (file)
@@ -46,8 +46,6 @@
 #include <asm/ldc.h>
 #include <asm/hypervisor.h>
 
-extern void calibrate_delay(void);
-
 int sparc64_multi_core __read_mostly;
 
 cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
index 60765e3..8649635 100644 (file)
@@ -277,6 +277,7 @@ EXPORT_SYMBOL(sys_getpid);
 EXPORT_SYMBOL(sys_geteuid);
 EXPORT_SYMBOL(sys_getuid);
 EXPORT_SYMBOL(sys_getegid);
+EXPORT_SYMBOL(sysctl_nr_open);
 EXPORT_SYMBOL(sys_getgid);
 EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(svr4_setcontext);
index b805890..adc62f4 100644 (file)
@@ -80,7 +80,8 @@ sys_call_table32:
        .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/        .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_ni_syscall, sys_eventfd, compat_sys_fallocate
+/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
+       .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime
 
 #endif /* CONFIG_COMPAT */
 
@@ -152,7 +153,8 @@ sys_call_table:
        .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .word sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
+/*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
+       .word sys_timerfd_settime, sys_timerfd_gettime
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -271,6 +273,7 @@ sunos_sys_table:
        .word sunos_nosys, sunos_nosys, sunos_nosys
        .word sunos_nosys
 /*310*/        .word sunos_nosys, sunos_nosys, sunos_nosys
-       .word sunos_nosys, sunos_nosys
+       .word sunos_nosys, sunos_nosys, sunos_nosys
+       .word sunos_nosys
 
 #endif
index 4352ee4..d204f1a 100644 (file)
@@ -1707,6 +1707,11 @@ static void __exit rtc_mini_exit(void)
        misc_deregister(&rtc_mini_dev);
 }
 
+int __devinit read_current_timer(unsigned long *timer_val)
+{
+       *timer_val = tick_ops->get_tick();
+       return 0;
+}
 
 module_init(rtc_mini_init);
 module_exit(rtc_mini_exit);
index 61be597..9311bfe 100644 (file)
@@ -624,7 +624,7 @@ asmlinkage int solaris_ulimit(int cmd, int val)
        case 3: /* UL_GMEMLIM */
                return current->signal->rlim[RLIMIT_DATA].rlim_cur;
        case 4: /* UL_GDESLIM */
-               return NR_OPEN;
+               return sysctl_nr_open;
        }
        return -EINVAL;
 }
index a9d32ce..f53123c 100644 (file)
@@ -859,7 +859,8 @@ asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
 
        SOLD("entry");
        lock_kernel();
-       if(fd >= NR_OPEN) goto out;
+       if (fd >= sysctl_nr_open)
+               goto out;
 
        fdt = files_fdtable(current->files);
        filp = fdt->fd[fd];
@@ -927,7 +928,8 @@ asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3)
 
        SOLD("entry");
        lock_kernel();
-       if(fd >= NR_OPEN) goto out;
+       if (fd >= sysctl_nr_open)
+               goto out;
 
        fdt = files_fdtable(current->files);
        filp = fdt->fd[fd];
index 4348211..e6728bd 100644 (file)
@@ -415,7 +415,7 @@ config HPET_TIMER
 
 config HPET_EMULATE_RTC
        def_bool y
-       depends on HPET_TIMER && (RTC=y || RTC=m)
+       depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y)
 
 # Mark as embedded because too many people got it wrong.
 # The code disables itself when not needed.
index d9313d9..f86a3c4 100644 (file)
@@ -637,7 +637,7 @@ void __init early_cpu_init(void)
 }
 
 /* Make sure %fs is initialized properly in idle threads */
-struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
+struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
 {
        memset(regs, 0, sizeof(struct pt_regs));
        regs->fs = __KERNEL_PERCPU;
index 404a6a2..7139b02 100644 (file)
@@ -83,8 +83,6 @@ static char cyrix_model_mult2[] __cpuinitdata = "12233445";
  * FIXME: our newer udelay uses the tsc. We don't need to frob with SLOP
  */
 
-extern void calibrate_delay(void) __init;
-
 static void __cpuinit check_cx686_slop(struct cpuinfo_x86 *c)
 {
        unsigned long flags;
index 5787a0c..579b9b7 100644 (file)
@@ -202,8 +202,6 @@ valid_k7:
        ;
 }
 
-extern void calibrate_delay(void);
-
 static atomic_t init_deasserted;
 
 static void __cpuinit smp_callin(void)
index aad9d95..4535e6d 100644 (file)
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/timex.h>
 #include <linux/preempt.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/processor.h>
 #include <asm/delay.h>
@@ -63,7 +65,7 @@ void use_tsc_delay(void)
        delay_fn = delay_tsc;
 }
 
-int read_current_timer(unsigned long *timer_val)
+int __devinit read_current_timer(unsigned long *timer_val)
 {
        if (delay_fn == delay_tsc) {
                rdtscl(*timer_val);
index 45cdd3f..bbc6105 100644 (file)
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/timex.h>
 #include <linux/preempt.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/delay.h>
 #include <asm/msr.h>
@@ -20,7 +22,7 @@
 #include <asm/smp.h>
 #endif
 
-int read_current_timer(unsigned long *timer_value)
+int __devinit read_current_timer(unsigned long *timer_value)
 {
        rdtscll(*timer_value);
        return 0;
index dffa786..3cc8eb2 100644 (file)
@@ -444,8 +444,6 @@ static __u32 __init setup_trampoline(void)
 static void __init start_secondary(void *unused)
 {
        __u8 cpuid = hard_smp_processor_id();
-       /* external functions not defined in the headers */
-       extern void calibrate_delay(void);
 
        cpu_init();
 
index 60d29fe..8df1e84 100644 (file)
@@ -204,7 +204,7 @@ again:
 }
 
 #ifndef CONFIG_GENERIC_CALIBRATE_DELAY
-void __devinit calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        loops_per_jiffy = CCOUNT_PER_JIFFY;
        printk("Calibrating delay loop (skipped)... "
index 047e533..0f62822 100644 (file)
@@ -35,7 +35,7 @@
  * @src: src page
  * @offset: offset in pages to start transaction
  * @len: length in bytes
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
  * @depend_tx: memcpy depends on the result of this transaction
  * @cb_fn: function to call when the memcpy completes
  * @cb_param: parameter to pass to the callback routine
@@ -46,33 +46,29 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY,
+                                                     &dest, 1, &src, 1, len);
        struct dma_device *device = chan ? chan->device : NULL;
-       int int_en = cb_fn ? 1 : 0;
-       struct dma_async_tx_descriptor *tx = device ?
-               device->device_prep_dma_memcpy(chan, len,
-               int_en) : NULL;
+       struct dma_async_tx_descriptor *tx = NULL;
 
-       if (tx) { /* run the memcpy asynchronously */
-               dma_addr_t addr;
-               enum dma_data_direction dir;
+       if (device) {
+               dma_addr_t dma_dest, dma_src;
+               unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
 
-               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
-
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_FROM_DEVICE;
-
-               addr = dma_map_page(device->dev, dest, dest_offset, len, dir);
-               tx->tx_set_dest(addr, tx, 0);
+               dma_dest = dma_map_page(device->dev, dest, dest_offset, len,
+                                       DMA_FROM_DEVICE);
 
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_TO_DEVICE;
+               dma_src = dma_map_page(device->dev, src, src_offset, len,
+                                      DMA_TO_DEVICE);
 
-               addr = dma_map_page(device->dev, src, src_offset, len, dir);
-               tx->tx_set_src(addr, tx, 0);
+               tx = device->device_prep_dma_memcpy(chan, dma_dest, dma_src,
+                                                   len, dma_prep_flags);
+       }
 
+       if (tx) {
+               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
                async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
-       } else { /* run the memcpy synchronously */
+       } else {
                void *dest_buf, *src_buf;
                pr_debug("%s: (sync) len: %zu\n", __FUNCTION__, len);
 
index 66ef635..09c0e83 100644 (file)
@@ -35,7 +35,7 @@
  * @val: fill value
  * @offset: offset in pages to start transaction
  * @len: length in bytes
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
  * @depend_tx: memset depends on the result of this transaction
  * @cb_fn: function to call when the memcpy completes
  * @cb_param: parameter to pass to the callback routine
@@ -46,24 +46,24 @@ async_memset(struct page *dest, int val, unsigned int offset,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET,
+                                                     &dest, 1, NULL, 0, len);
        struct dma_device *device = chan ? chan->device : NULL;
-       int int_en = cb_fn ? 1 : 0;
-       struct dma_async_tx_descriptor *tx = device ?
-               device->device_prep_dma_memset(chan, val, len,
-                       int_en) : NULL;
+       struct dma_async_tx_descriptor *tx = NULL;
 
-       if (tx) { /* run the memset asynchronously */
-               dma_addr_t dma_addr;
-               enum dma_data_direction dir;
+       if (device) {
+               dma_addr_t dma_dest;
+               unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
 
-               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_FROM_DEVICE;
+               dma_dest = dma_map_page(device->dev, dest, offset, len,
+                                       DMA_FROM_DEVICE);
 
-               dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
-               tx->tx_set_dest(dma_addr, tx, 0);
+               tx = device->device_prep_dma_memset(chan, dma_dest, val, len,
+                                                   dma_prep_flags);
+       }
 
+       if (tx) {
+               pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
                async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
        } else { /* run the memset synchronously */
                void *dest_buf;
index bc18cbb..5628821 100644 (file)
@@ -57,8 +57,7 @@ static struct chan_ref_percpu *channel_table[DMA_TX_TYPE_END];
  */
 static spinlock_t async_tx_lock;
 
-static struct list_head
-async_tx_master_list = LIST_HEAD_INIT(async_tx_master_list);
+static LIST_HEAD(async_tx_master_list);
 
 /* async_tx_issue_pending_all - start all transactions on all channels */
 void async_tx_issue_pending_all(void)
@@ -362,13 +361,13 @@ static void __exit async_tx_exit(void)
 }
 
 /**
- * async_tx_find_channel - find a channel to carry out the operation or let
+ * __async_tx_find_channel - find a channel to carry out the operation or let
  *     the transaction execute synchronously
  * @depend_tx: transaction dependency
  * @tx_type: transaction type
  */
 struct dma_chan *
-async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+__async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
        enum dma_transaction_type tx_type)
 {
        /* see if we can keep the chain on one channel */
@@ -384,7 +383,7 @@ async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
        } else
                return NULL;
 }
-EXPORT_SYMBOL_GPL(async_tx_find_channel);
+EXPORT_SYMBOL_GPL(__async_tx_find_channel);
 #else
 static int __init async_tx_init(void)
 {
index 2575f67..2259a4f 100644 (file)
 #include <linux/raid/xor.h>
 #include <linux/async_tx.h>
 
-static void
-do_async_xor(struct dma_async_tx_descriptor *tx, struct dma_device *device,
+/* do_async_xor - dma map the pages and perform the xor with an engine.
+ *     This routine is marked __always_inline so it can be compiled away
+ *     when CONFIG_DMA_ENGINE=n
+ */
+static __always_inline struct dma_async_tx_descriptor *
+do_async_xor(struct dma_device *device,
        struct dma_chan *chan, struct page *dest, struct page **src_list,
        unsigned int offset, unsigned int src_cnt, size_t len,
        enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       dma_addr_t dma_addr;
-       enum dma_data_direction dir;
+       dma_addr_t dma_dest;
+       dma_addr_t *dma_src = (dma_addr_t *) src_list;
+       struct dma_async_tx_descriptor *tx;
        int i;
+       unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
 
        pr_debug("%s: len: %zu\n", __FUNCTION__, len);
 
-       dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-               DMA_NONE : DMA_FROM_DEVICE;
-
-       dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
-       tx->tx_set_dest(dma_addr, tx, 0);
-
-       dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-               DMA_NONE : DMA_TO_DEVICE;
+       dma_dest = dma_map_page(device->dev, dest, offset, len,
+                               DMA_FROM_DEVICE);
 
-       for (i = 0; i < src_cnt; i++) {
-               dma_addr = dma_map_page(device->dev, src_list[i],
-                       offset, len, dir);
-               tx->tx_set_src(dma_addr, tx, i);
+       for (i = 0; i < src_cnt; i++)
+               dma_src[i] = dma_map_page(device->dev, src_list[i], offset,
+                                         len, DMA_TO_DEVICE);
+
+       /* Since we have clobbered the src_list we are committed
+        * to doing this asynchronously.  Drivers force forward progress
+        * in case they can not provide a descriptor
+        */
+       tx = device->device_prep_dma_xor(chan, dma_dest, dma_src, src_cnt, len,
+                                        dma_prep_flags);
+       if (!tx) {
+               if (depend_tx)
+                       dma_wait_for_async_tx(depend_tx);
+
+               while (!tx)
+                       tx = device->device_prep_dma_xor(chan, dma_dest,
+                                                        dma_src, src_cnt, len,
+                                                        dma_prep_flags);
        }
 
        async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+
+       return tx;
 }
 
 static void
@@ -102,7 +118,7 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
  * @src_cnt: number of source pages
  * @len: length in bytes
  * @flags: ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DEST,
- *     ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ *     ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
  * @depend_tx: xor depends on the result of this transaction.
  * @cb_fn: function to call when the xor completes
  * @cb_param: parameter to pass to the callback routine
@@ -113,14 +129,16 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR,
+                                                     &dest, 1, src_list,
+                                                     src_cnt, len);
        struct dma_device *device = chan ? chan->device : NULL;
        struct dma_async_tx_descriptor *tx = NULL;
        dma_async_tx_callback _cb_fn;
        void *_cb_param;
        unsigned long local_flags;
        int xor_src_cnt;
-       int i = 0, src_off = 0, int_en;
+       int i = 0, src_off = 0;
 
        BUG_ON(src_cnt <= 1);
 
@@ -140,20 +158,11 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
                                _cb_param = cb_param;
                        }
 
-                       int_en = _cb_fn ? 1 : 0;
-
-                       tx = device->device_prep_dma_xor(
-                               chan, xor_src_cnt, len, int_en);
-
-                       if (tx) {
-                               do_async_xor(tx, device, chan, dest,
-                               &src_list[src_off], offset, xor_src_cnt, len,
-                               local_flags, depend_tx, _cb_fn,
-                               _cb_param);
-                       } else /* fall through */
-                               goto xor_sync;
+                       tx = do_async_xor(device, chan, dest,
+                                         &src_list[src_off], offset,
+                                         xor_src_cnt, len, local_flags,
+                                         depend_tx, _cb_fn, _cb_param);
                } else { /* run the xor synchronously */
-xor_sync:
                        /* in the sync case the dest is an implied source
                         * (assumes the dest is at the src_off index)
                         */
@@ -242,7 +251,7 @@ static int page_is_zero(struct page *p, unsigned int offset, size_t len)
  * @src_cnt: number of source pages
  * @len: length in bytes
  * @result: 0 if sum == 0 else non-zero
- * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
  * @depend_tx: xor depends on the result of this transaction.
  * @cb_fn: function to call when the xor completes
  * @cb_param: parameter to pass to the callback routine
@@ -254,29 +263,36 @@ async_xor_zero_sum(struct page *dest, struct page **src_list,
        struct dma_async_tx_descriptor *depend_tx,
        dma_async_tx_callback cb_fn, void *cb_param)
 {
-       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM);
+       struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM,
+                                                     &dest, 1, src_list,
+                                                     src_cnt, len);
        struct dma_device *device = chan ? chan->device : NULL;
-       int int_en = cb_fn ? 1 : 0;
-       struct dma_async_tx_descriptor *tx = device ?
-               device->device_prep_dma_zero_sum(chan, src_cnt, len, result,
-                       int_en) : NULL;
-       int i;
+       struct dma_async_tx_descriptor *tx = NULL;
 
        BUG_ON(src_cnt <= 1);
 
-       if (tx) {
-               dma_addr_t dma_addr;
-               enum dma_data_direction dir;
+       if (device) {
+               dma_addr_t *dma_src = (dma_addr_t *) src_list;
+               unsigned long dma_prep_flags = cb_fn ? DMA_PREP_INTERRUPT : 0;
+               int i;
 
                pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
 
-               dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
-                       DMA_NONE : DMA_TO_DEVICE;
-
-               for (i = 0; i < src_cnt; i++) {
-                       dma_addr = dma_map_page(device->dev, src_list[i],
-                               offset, len, dir);
-                       tx->tx_set_src(dma_addr, tx, i);
+               for (i = 0; i < src_cnt; i++)
+                       dma_src[i] = dma_map_page(device->dev, src_list[i],
+                                                 offset, len, DMA_TO_DEVICE);
+
+               tx = device->device_prep_dma_zero_sum(chan, dma_src, src_cnt,
+                                                     len, result,
+                                                     dma_prep_flags);
+               if (!tx) {
+                       if (depend_tx)
+                               dma_wait_for_async_tx(depend_tx);
+
+                       while (!tx)
+                               tx = device->device_prep_dma_zero_sum(chan,
+                                       dma_src, src_cnt, len, result,
+                                       dma_prep_flags);
                }
 
                async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
@@ -311,6 +327,16 @@ EXPORT_SYMBOL_GPL(async_xor_zero_sum);
 
 static int __init async_xor_init(void)
 {
+       #ifdef CONFIG_DMA_ENGINE
+       /* To conserve stack space the input src_list (array of page pointers)
+        * is reused to hold the array of dma addresses passed to the driver.
+        * This conversion is only possible when dma_addr_t is less than the
+        * the size of a pointer.  HIGHMEM64G is known to violate this
+        * assumption.
+        */
+       BUILD_BUG_ON(sizeof(dma_addr_t) > sizeof(struct page *));
+       #endif
+
        return 0;
 }
 
index 27c8d56..29e71bd 100644 (file)
@@ -679,24 +679,20 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
 
        /* cross check port_map and cap.n_ports */
        if (port_map) {
-               u32 tmp_port_map = port_map;
-               int n_ports = ahci_nr_ports(cap);
+               int map_ports = 0;
 
-               for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
-                       if (tmp_port_map & (1 << i)) {
-                               n_ports--;
-                               tmp_port_map &= ~(1 << i);
-                       }
-               }
+               for (i = 0; i < AHCI_MAX_PORTS; i++)
+                       if (port_map & (1 << i))
+                               map_ports++;
 
-               /* If n_ports and port_map are inconsistent, whine and
-                * clear port_map and let it be generated from n_ports.
+               /* If PI has more ports than n_ports, whine, clear
+                * port_map and let it be generated from n_ports.
                 */
-               if (n_ports || tmp_port_map) {
+               if (map_ports > ahci_nr_ports(cap)) {
                        dev_printk(KERN_WARNING, &pdev->dev,
-                                  "nr_ports (%u) and implemented port map "
-                                  "(0x%x) don't match, using nr_ports\n",
-                                  ahci_nr_ports(cap), port_map);
+                                  "implemented port map (0x%x) contains more "
+                                  "ports than nr_ports (%u), using nr_ports\n",
+                                  port_map, ahci_nr_ports(cap));
                        port_map = 0;
                }
        }
@@ -2201,7 +2197,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct device *dev = &pdev->dev;
        struct ahci_host_priv *hpriv;
        struct ata_host *host;
-       int i, rc;
+       int n_ports, i, rc;
 
        VPRINTK("ENTER\n");
 
@@ -2255,7 +2251,14 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (hpriv->cap & HOST_CAP_PMP)
                pi.flags |= ATA_FLAG_PMP;
 
-       host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+       /* CAP.NP sometimes indicate the index of the last enabled
+        * port, at other times, that of the last possible port, so
+        * determining the maximum port number requires looking at
+        * both CAP.NP and port_map.
+        */
+       n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
        if (!host)
                return -ENOMEM;
        host->iomap = pcim_iomap_table(pdev);
index 4b99ed0..9c2515f 100644 (file)
@@ -1603,7 +1603,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
  *     Zero on success, or -ERRNO value.
  */
 
-static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit piix_init_one(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
 {
        static int printed_version;
        struct device *dev = &pdev->dev;
index 361cf50..3011919 100644 (file)
@@ -4154,8 +4154,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        /* NCQ is broken */
        { "Maxtor *",           "BANC*",        ATA_HORKAGE_NONCQ },
        { "Maxtor 7V300F0",     "VA111630",     ATA_HORKAGE_NONCQ },
-       { "HITACHI HDS7250SASUN500G*", NULL,    ATA_HORKAGE_NONCQ },
-       { "HITACHI HDS7225SBSUN250G*", NULL,    ATA_HORKAGE_NONCQ },
        { "ST380817AS",         "3.42",         ATA_HORKAGE_NONCQ },
        { "ST3160023AS",        "3.42",         ATA_HORKAGE_NONCQ },
 
index 938f48a..408da30 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 
 static int __devinit pata_of_platform_probe(struct of_device *ofdev,
                                            const struct of_device_id *match)
index 224bb6c..aad7adc 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/ata.h>
 #include <linux/libata.h>
 #include <linux/platform_device.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 
 #define DRV_NAME "pata_platform"
 #define DRV_VERSION "1.2"
index 922d7b2..efcb66b 100644 (file)
@@ -355,8 +355,8 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
                        ata_port_printk(qc->ap, KERN_ERR,
                                        "s/g len unaligned : 0x%x\n", sg_len);
 
-               if ((num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1)) &&
-                   (qc->n_iter + 1 != qc->n_elem)) {
+               if (num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1) &&
+                   sg_next(sg) != NULL) {
                        VPRINTK("setting indirect prde\n");
                        prd_ptr_to_indirect_ext = prd;
                        prd->dba = cpu_to_le32(indirect_ext_segment_paddr);
index 3c1b5c9..080b836 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -179,6 +182,8 @@ enum {
 
        HC_MAIN_IRQ_CAUSE_OFS   = 0x1d60,
        HC_MAIN_IRQ_MASK_OFS    = 0x1d64,
+       HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
+       HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
        PORT0_ERR               = (1 << 0),     /* shift by port # */
        PORT0_DONE              = (1 << 1),     /* shift by port # */
        HC0_IRQ_PEND            = 0x1ff,        /* bits 0-8 = HC0's ports */
@@ -194,11 +199,13 @@ enum {
        TWSI_INT                = (1 << 24),
        HC_MAIN_RSVD            = (0x7f << 25), /* bits 31-25 */
        HC_MAIN_RSVD_5          = (0x1fff << 19), /* bits 31-19 */
+       HC_MAIN_RSVD_SOC        = (0x3fffffb << 6),     /* bits 31-9, 7-6 */
        HC_MAIN_MASKED_IRQS     = (TRAN_LO_DONE | TRAN_HI_DONE |
                                   PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
                                   HC_MAIN_RSVD),
        HC_MAIN_MASKED_IRQS_5   = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
                                   HC_MAIN_RSVD_5),
+       HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC),
 
        /* SATAHC registers */
        HC_CFG_OFS              = 0,
@@ -368,6 +375,7 @@ enum chip_type {
        chip_608x,
        chip_6042,
        chip_7042,
+       chip_soc,
 };
 
 /* Command ReQuest Block: 32B */
@@ -424,6 +432,10 @@ struct mv_host_priv {
        u32                     hp_flags;
        struct mv_port_signal   signal[8];
        const struct mv_hw_ops  *ops;
+       int                     n_ports;
+       void __iomem            *base;
+       void __iomem            *main_cause_reg_addr;
+       void __iomem            *main_mask_reg_addr;
        u32                     irq_cause_ofs;
        u32                     irq_mask_ofs;
        u32                     unmask_all_irqs;
@@ -482,6 +494,15 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
 static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
                        unsigned int n_hc);
 static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+static void mv_soc_enable_leds(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio);
+static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
+                                     void __iomem *mmio);
+static int mv_soc_reset_hc(struct mv_host_priv *hpriv,
+                                 void __iomem *mmio, unsigned int n_hc);
+static void mv_soc_reset_flash(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio);
+static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio);
 static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
 static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
                             unsigned int port_no);
@@ -661,6 +682,12 @@ static const struct ata_port_info mv_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
        },
+       {  /* chip_soc */
+               .flags = MV_COMMON_FLAGS | MV_FLAG_SOC,
+               .pio_mask = 0x1f,      /* pio0-4 */
+               .udma_mask = ATA_UDMA6,
+               .port_ops = &mv_iie_ops,
+       },
 };
 
 static const struct pci_device_id mv_pci_tbl[] = {
@@ -711,6 +738,15 @@ static const struct mv_hw_ops mv6xxx_ops = {
        .reset_bus              = mv_reset_pci_bus,
 };
 
+static const struct mv_hw_ops mv_soc_ops = {
+       .phy_errata             = mv6_phy_errata,
+       .enable_leds            = mv_soc_enable_leds,
+       .read_preamp            = mv_soc_read_preamp,
+       .reset_hc               = mv_soc_reset_hc,
+       .reset_flash            = mv_soc_reset_flash,
+       .reset_bus              = mv_soc_reset_bus,
+};
+
 /*
  * Functions
  */
@@ -749,9 +785,15 @@ static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
                (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
 }
 
+static inline void __iomem *mv_host_base(struct ata_host *host)
+{
+       struct mv_host_priv *hpriv = host->private_data;
+       return hpriv->base;
+}
+
 static inline void __iomem *mv_ap_base(struct ata_port *ap)
 {
-       return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
+       return mv_port_base(mv_host_base(ap->host), ap->port_no);
 }
 
 static inline int mv_get_hc_count(unsigned long port_flags)
@@ -1649,16 +1691,21 @@ static void mv_intr_edma(struct ata_port *ap)
  */
 static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
 {
-       void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->base;
        void __iomem *hc_mmio = mv_hc_base(mmio, hc);
        u32 hc_irq_cause;
-       int port, port0;
+       int port, port0, last_port;
 
        if (hc == 0)
                port0 = 0;
        else
                port0 = MV_PORTS_PER_HC;
 
+       if (HAS_PCI(host))
+               last_port = port0 + MV_PORTS_PER_HC;
+       else
+               last_port = port0 + hpriv->n_ports;
        /* we'll need the HC success int register in most cases */
        hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
        if (!hc_irq_cause)
@@ -1669,7 +1716,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
        VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
                hc, relevant, hc_irq_cause);
 
-       for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+       for (port = port0; port < port0 + last_port; port++) {
                struct ata_port *ap = host->ports[port];
                struct mv_port_priv *pp = ap->private_data;
                int have_err_bits, hard_port, shift;
@@ -1764,13 +1811,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
 static irqreturn_t mv_interrupt(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
+       struct mv_host_priv *hpriv = host->private_data;
        unsigned int hc, handled = 0, n_hcs;
-       void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+       void __iomem *mmio = hpriv->base;
        u32 irq_stat, irq_mask;
 
        spin_lock(&host->lock);
-       irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
-       irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
+
+       irq_stat = readl(hpriv->main_cause_reg_addr);
+       irq_mask = readl(hpriv->main_mask_reg_addr);
 
        /* check the cases where we either have nothing pending or have read
         * a bogus register value which can indicate HW removal or PCI fault
@@ -1827,7 +1876,8 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
 
 static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       void __iomem *mmio = hpriv->base;
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
@@ -1840,7 +1890,8 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 
 static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       void __iomem *mmio = hpriv->base;
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
@@ -2178,6 +2229,93 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
        writel(m2, port_mmio + PHY_MODE2);
 }
 
+/* TODO: use the generic LED interface to configure the SATA Presence */
+/* & Acitivy LEDs on the board */
+static void mv_soc_enable_leds(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio)
+{
+       return;
+}
+
+static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx,
+                          void __iomem *mmio)
+{
+       void __iomem *port_mmio;
+       u32 tmp;
+
+       port_mmio = mv_port_base(mmio, idx);
+       tmp = readl(port_mmio + PHY_MODE2);
+
+       hpriv->signal[idx].amps = tmp & 0x700;  /* bits 10:8 */
+       hpriv->signal[idx].pre = tmp & 0xe0;    /* bits 7:5 */
+}
+
+#undef ZERO
+#define ZERO(reg) writel(0, port_mmio + (reg))
+static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
+                                       void __iomem *mmio, unsigned int port)
+{
+       void __iomem *port_mmio = mv_port_base(mmio, port);
+
+       writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+
+       mv_channel_reset(hpriv, mmio, port);
+
+       ZERO(0x028);            /* command */
+       writel(0x101f, port_mmio + EDMA_CFG_OFS);
+       ZERO(0x004);            /* timer */
+       ZERO(0x008);            /* irq err cause */
+       ZERO(0x00c);            /* irq err mask */
+       ZERO(0x010);            /* rq bah */
+       ZERO(0x014);            /* rq inp */
+       ZERO(0x018);            /* rq outp */
+       ZERO(0x01c);            /* respq bah */
+       ZERO(0x024);            /* respq outp */
+       ZERO(0x020);            /* respq inp */
+       ZERO(0x02c);            /* test control */
+       writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+}
+
+#undef ZERO
+
+#define ZERO(reg) writel(0, hc_mmio + (reg))
+static void mv_soc_reset_one_hc(struct mv_host_priv *hpriv,
+                                      void __iomem *mmio)
+{
+       void __iomem *hc_mmio = mv_hc_base(mmio, 0);
+
+       ZERO(0x00c);
+       ZERO(0x010);
+       ZERO(0x014);
+
+}
+
+#undef ZERO
+
+static int mv_soc_reset_hc(struct mv_host_priv *hpriv,
+                                 void __iomem *mmio, unsigned int n_hc)
+{
+       unsigned int port;
+
+       for (port = 0; port < hpriv->n_ports; port++)
+               mv_soc_reset_hc_port(hpriv, mmio, port);
+
+       mv_soc_reset_one_hc(hpriv, mmio);
+
+       return 0;
+}
+
+static void mv_soc_reset_flash(struct mv_host_priv *hpriv,
+                                     void __iomem *mmio)
+{
+       return;
+}
+
+static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
+{
+       return;
+}
+
 static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
                             unsigned int port_no)
 {
@@ -2342,7 +2480,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
 {
        struct ata_port *ap = link->ap;
        struct mv_host_priv *hpriv = ap->host->private_data;
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       void __iomem *mmio = hpriv->base;
 
        mv_stop_dma(ap);
 
@@ -2383,7 +2521,7 @@ static void mv_error_handler(struct ata_port *ap)
 
 static void mv_eh_freeze(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
        unsigned int hc = (ap->port_no > 3) ? 1 : 0;
        u32 tmp, mask;
        unsigned int shift;
@@ -2397,13 +2535,14 @@ static void mv_eh_freeze(struct ata_port *ap)
        mask = 0x3 << shift;
 
        /* disable assertion of portN err, done events */
-       tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
-       writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
+       tmp = readl(hpriv->main_mask_reg_addr);
+       writelfl(tmp & ~mask, hpriv->main_mask_reg_addr);
 }
 
 static void mv_eh_thaw(struct ata_port *ap)
 {
-       void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       void __iomem *mmio = hpriv->base;
        unsigned int hc = (ap->port_no > 3) ? 1 : 0;
        void __iomem *hc_mmio = mv_hc_base(mmio, hc);
        void __iomem *port_mmio = mv_ap_base(ap);
@@ -2430,8 +2569,8 @@ static void mv_eh_thaw(struct ata_port *ap)
        writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
 
        /* enable assertion of portN err, done events */
-       tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
-       writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
+       tmp = readl(hpriv->main_mask_reg_addr);
+       writelfl(tmp | mask, hpriv->main_mask_reg_addr);
 }
 
 /**
@@ -2598,9 +2737,13 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
                        break;
                }
                break;
+       case chip_soc:
+               hpriv->ops = &mv_soc_ops;
+               hp_flags |= MV_HP_ERRATA_60X1C0;
+               break;
 
        default:
-               dev_printk(KERN_ERR, &pdev->dev,
+               dev_printk(KERN_ERR, host->dev,
                           "BUG: invalid board index %u\n", board_idx);
                return 1;
        }
@@ -2633,15 +2776,25 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
 static int mv_init_host(struct ata_host *host, unsigned int board_idx)
 {
        int rc = 0, n_hc, port, hc;
-       void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
        struct mv_host_priv *hpriv = host->private_data;
-
-       /* global interrupt mask */
-       writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
+       void __iomem *mmio = hpriv->base;
 
        rc = mv_chip_id(host, board_idx);
        if (rc)
-               goto done;
+       goto done;
+
+       if (HAS_PCI(host)) {
+               hpriv->main_cause_reg_addr = hpriv->base +
+                 HC_MAIN_IRQ_CAUSE_OFS;
+               hpriv->main_mask_reg_addr = hpriv->base + HC_MAIN_IRQ_MASK_OFS;
+       } else {
+               hpriv->main_cause_reg_addr = hpriv->base +
+                 HC_SOC_MAIN_IRQ_CAUSE_OFS;
+               hpriv->main_mask_reg_addr = hpriv->base +
+                 HC_SOC_MAIN_IRQ_MASK_OFS;
+       }
+       /* global interrupt mask */
+       writel(0, hpriv->main_mask_reg_addr);
 
        n_hc = mv_get_hc_count(host->ports[0]->flags);
 
@@ -2672,13 +2825,15 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
        for (port = 0; port < host->n_ports; port++) {
                struct ata_port *ap = host->ports[port];
                void __iomem *port_mmio = mv_port_base(mmio, port);
-               unsigned int offset = port_mmio - mmio;
 
                mv_port_init(&ap->ioaddr, port_mmio);
 
 #ifdef CONFIG_PCI
-               ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
-               ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+               if (HAS_PCI(host)) {
+                       unsigned int offset = port_mmio - mmio;
+                       ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+                       ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+               }
 #endif
        }
 
@@ -2694,35 +2849,141 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
                writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
        }
 
-       /* Clear any currently outstanding host interrupt conditions */
-       writelfl(0, mmio + hpriv->irq_cause_ofs);
+       if (HAS_PCI(host)) {
+               /* Clear any currently outstanding host interrupt conditions */
+               writelfl(0, mmio + hpriv->irq_cause_ofs);
 
-       /* and unmask interrupt generation for host regs */
-       writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
+               /* and unmask interrupt generation for host regs */
+               writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
+               if (IS_GEN_I(hpriv))
+                       writelfl(~HC_MAIN_MASKED_IRQS_5,
+                                hpriv->main_mask_reg_addr);
+               else
+                       writelfl(~HC_MAIN_MASKED_IRQS,
+                                hpriv->main_mask_reg_addr);
+
+               VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
+                       "PCI int cause/mask=0x%08x/0x%08x\n",
+                       readl(hpriv->main_cause_reg_addr),
+                       readl(hpriv->main_mask_reg_addr),
+                       readl(mmio + hpriv->irq_cause_ofs),
+                       readl(mmio + hpriv->irq_mask_ofs));
+       } else {
+               writelfl(~HC_MAIN_MASKED_IRQS_SOC,
+                        hpriv->main_mask_reg_addr);
+               VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
+                       readl(hpriv->main_cause_reg_addr),
+                       readl(hpriv->main_mask_reg_addr));
+       }
+done:
+       return rc;
+}
 
-       if (IS_GEN_I(hpriv))
-               writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
-       else
-               writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
+/**
+ *      mv_platform_probe - handle a positive probe of an soc Marvell
+ *      host
+ *      @pdev: platform device found
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static int mv_platform_probe(struct platform_device *pdev)
+{
+       static int printed_version;
+       const struct mv_sata_platform_data *mv_platform_data;
+       const struct ata_port_info *ppi[] =
+           { &mv_port_info[chip_soc], NULL };
+       struct ata_host *host;
+       struct mv_host_priv *hpriv;
+       struct resource *res;
+       int n_ports, rc;
 
-       VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
-               "PCI int cause/mask=0x%08x/0x%08x\n",
-               readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
-               readl(mmio + HC_MAIN_IRQ_MASK_OFS),
-               readl(mmio + hpriv->irq_cause_ofs),
-               readl(mmio + hpriv->irq_mask_ofs));
+       if (!printed_version++)
+               dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
-done:
-       return rc;
+       /*
+        * Simple resource validation ..
+        */
+       if (unlikely(pdev->num_resources != 2)) {
+               dev_err(&pdev->dev, "invalid number of resources\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Get the register base first
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL)
+               return -EINVAL;
+
+       /* allocate host */
+       mv_platform_data = pdev->dev.platform_data;
+       n_ports = mv_platform_data->n_ports;
+
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+       hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+
+       if (!host || !hpriv)
+               return -ENOMEM;
+       host->private_data = hpriv;
+       hpriv->n_ports = n_ports;
+
+       host->iomap = NULL;
+       hpriv->base = ioremap(res->start, res->end - res->start + 1);
+       hpriv->base -= MV_SATAHC0_REG_BASE;
+
+       /* initialize adapter */
+       rc = mv_init_host(host, chip_soc);
+       if (rc)
+               return rc;
+
+       dev_printk(KERN_INFO, &pdev->dev,
+                  "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
+                  host->n_ports);
+
+       return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
+                                IRQF_SHARED, &mv6_sht);
+}
+
+/*
+ *
+ *      mv_platform_remove    -       unplug a platform interface
+ *      @pdev: platform device
+ *
+ *      A platform bus SATA device has been unplugged. Perform the needed
+ *      cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit mv_platform_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ata_host *host = dev_get_drvdata(dev);
+       struct mv_host_priv *hpriv = host->private_data;
+       void __iomem *base = hpriv->base;
+
+       ata_host_detach(host);
+       iounmap(base);
+       return 0;
 }
 
+static struct platform_driver mv_platform_driver = {
+       .probe                  = mv_platform_probe,
+       .remove                 = __devexit_p(mv_platform_remove),
+       .driver                 = {
+                                  .name = DRV_NAME,
+                                  .owner = THIS_MODULE,
+                                 },
+};
+
+
 #ifdef CONFIG_PCI
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int mv_pci_init_one(struct pci_dev *pdev,
+                          const struct pci_device_id *ent);
+
 
 static struct pci_driver mv_pci_driver = {
        .name                   = DRV_NAME,
        .id_table               = mv_pci_tbl,
-       .probe                  = mv_init_one,
+       .probe                  = mv_pci_init_one,
        .remove                 = ata_pci_remove_one,
 };
 
@@ -2828,14 +3089,15 @@ static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
 }
 
 /**
- *      mv_init_one - handle a positive probe of a Marvell host
+ *      mv_pci_init_one - handle a positive probe of a PCI Marvell host
  *      @pdev: PCI device found
  *      @ent: PCI device ID entry for the matched host
  *
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int mv_pci_init_one(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        static int printed_version;
        unsigned int board_idx = (unsigned int)ent->driver_data;
@@ -2855,6 +3117,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!host || !hpriv)
                return -ENOMEM;
        host->private_data = hpriv;
+       hpriv->n_ports = n_ports;
 
        /* acquire resources */
        rc = pcim_enable_device(pdev);
@@ -2867,6 +3130,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
        host->iomap = pcim_iomap_table(pdev);
+       hpriv->base = host->iomap[MV_PRIMARY_BAR];
 
        rc = pci_go_64(pdev);
        if (rc)
@@ -2895,11 +3159,22 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 }
 #endif
 
+static int mv_platform_probe(struct platform_device *pdev);
+static int __devexit mv_platform_remove(struct platform_device *pdev);
+
 static int __init mv_init(void)
 {
        int rc = -ENODEV;
 #ifdef CONFIG_PCI
        rc = pci_register_driver(&mv_pci_driver);
+       if (rc < 0)
+               return rc;
+#endif
+       rc = platform_driver_register(&mv_platform_driver);
+
+#ifdef CONFIG_PCI
+       if (rc < 0)
+               pci_unregister_driver(&mv_pci_driver);
 #endif
        return rc;
 }
@@ -2909,6 +3184,7 @@ static void __exit mv_exit(void)
 #ifdef CONFIG_PCI
        pci_unregister_driver(&mv_pci_driver);
 #endif
+       platform_driver_unregister(&mv_platform_driver);
 }
 
 MODULE_AUTHOR("Brett Russ");
index bfe92a4..ed5473b 100644 (file)
@@ -247,6 +247,7 @@ struct nv_adma_port_priv {
        void __iomem            *ctl_block;
        void __iomem            *gen_block;
        void __iomem            *notifier_clear_block;
+       u64                     adma_dma_mask;
        u8                      flags;
        int                     last_issue_ncq;
 };
@@ -715,9 +716,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
 {
        struct ata_port *ap = ata_shost_to_port(sdev->host);
        struct nv_adma_port_priv *pp = ap->private_data;
+       struct nv_adma_port_priv *port0, *port1;
+       struct scsi_device *sdev0, *sdev1;
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u64 bounce_limit;
-       unsigned long segment_boundary;
+       unsigned long segment_boundary, flags;
        unsigned short sg_tablesize;
        int rc;
        int adma_enable;
@@ -729,6 +731,8 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                /* Not a proper libata device, ignore */
                return rc;
 
+       spin_lock_irqsave(ap->lock, flags);
+
        if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
                /*
                 * NVIDIA reports that ADMA mode does not support ATAPI commands.
@@ -737,7 +741,6 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                 * Restrict DMA parameters as required by the legacy interface
                 * when an ATAPI device is connected.
                 */
-               bounce_limit = ATA_DMA_MASK;
                segment_boundary = ATA_DMA_BOUNDARY;
                /* Subtract 1 since an extra entry may be needed for padding, see
                   libata-scsi.c */
@@ -748,7 +751,6 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
                adma_enable = 0;
                nv_adma_register_mode(ap);
        } else {
-               bounce_limit = *ap->dev->dma_mask;
                segment_boundary = NV_ADMA_DMA_BOUNDARY;
                sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN;
                adma_enable = 1;
@@ -774,12 +776,49 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
        if (current_reg != new_reg)
                pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg);
 
-       blk_queue_bounce_limit(sdev->request_queue, bounce_limit);
+       port0 = ap->host->ports[0]->private_data;
+       port1 = ap->host->ports[1]->private_data;
+       sdev0 = ap->host->ports[0]->link.device[0].sdev;
+       sdev1 = ap->host->ports[1]->link.device[0].sdev;
+       if ((port0->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+           (port1->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+               /** We have to set the DMA mask to 32-bit if either port is in
+                   ATAPI mode, since they are on the same PCI device which is
+                   used for DMA mapping. If we set the mask we also need to set
+                   the bounce limit on both ports to ensure that the block
+                   layer doesn't feed addresses that cause DMA mapping to
+                   choke. If either SCSI device is not allocated yet, it's OK
+                   since that port will discover its correct setting when it
+                   does get allocated.
+                   Note: Setting 32-bit mask should not fail. */
+               if (sdev0)
+                       blk_queue_bounce_limit(sdev0->request_queue,
+                                              ATA_DMA_MASK);
+               if (sdev1)
+                       blk_queue_bounce_limit(sdev1->request_queue,
+                                              ATA_DMA_MASK);
+
+               pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       } else {
+               /** This shouldn't fail as it was set to this value before */
+               pci_set_dma_mask(pdev, pp->adma_dma_mask);
+               if (sdev0)
+                       blk_queue_bounce_limit(sdev0->request_queue,
+                                              pp->adma_dma_mask);
+               if (sdev1)
+                       blk_queue_bounce_limit(sdev1->request_queue,
+                                              pp->adma_dma_mask);
+       }
+
        blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
        blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
        ata_port_printk(ap, KERN_INFO,
-               "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
-               (unsigned long long)bounce_limit, segment_boundary, sg_tablesize);
+               "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
+               (unsigned long long)*ap->host->dev->dma_mask,
+               segment_boundary, sg_tablesize);
+
+       spin_unlock_irqrestore(ap->lock, flags);
+
        return rc;
 }
 
@@ -1140,10 +1179,20 @@ static int nv_adma_port_start(struct ata_port *ap)
        void *mem;
        dma_addr_t mem_dma;
        void __iomem *mmio;
+       struct pci_dev *pdev = to_pci_dev(dev);
        u16 tmp;
 
        VPRINTK("ENTER\n");
 
+       /* Ensure DMA mask is set to 32-bit before allocating legacy PRD and
+          pad buffers */
+       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+
        rc = ata_port_start(ap);
        if (rc)
                return rc;
@@ -1159,6 +1208,15 @@ static int nv_adma_port_start(struct ata_port *ap)
        pp->notifier_clear_block = pp->gen_block +
               NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no);
 
+       /* Now that the legacy PRD and padding buffer are allocated we can
+          safely raise the DMA mask to allocate the CPB/APRD table.
+          These are allowed to fail since we store the value that ends up
+          being used to set as the bounce limit in slave_config later if
+          needed. */
+       pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+       pp->adma_dma_mask = *dev->dma_mask;
+
        mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
                                  &mem_dma, GFP_KERNEL);
        if (!mem)
@@ -2417,12 +2475,6 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        hpriv->type = type;
        host->private_data = hpriv;
 
-       /* set 64bit dma masks, may fail */
-       if (type == ADMA) {
-               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0)
-                       pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
-       }
-
        /* request and iomap NV_MMIO_BAR */
        rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
        if (rc)
index 3ef072f..30caa03 100644 (file)
@@ -30,8 +30,6 @@
  *  Hardware documentation available under NDA.
  *
  *
- *  To-do list:
- *  - VT6421 PATA support
  *
  */
 
index c5885f5..499b003 100644 (file)
@@ -110,7 +110,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
  *
  * Initialize and register the CPU device.
  */
-int __devinit register_cpu(struct cpu *cpu, int num)
+int __cpuinit register_cpu(struct cpu *cpu, int num)
 {
        int error;
        cpu->node_id = cpu_to_node(num);
index 94268c7..4249950 100644 (file)
@@ -90,7 +90,7 @@ static struct atari_disk_type {
        unsigned        blocks;         /* total number of blocks */
        unsigned        fdc_speed;      /* fdc_speed setting */
        unsigned        stretch;        /* track doubling ? */
-} disk_type[] = {
+} atari_disk_type[] = {
        { "d360",  9, 720, 0, 0},       /*  0: 360kB diskette */
        { "D360",  9, 720, 0, 1},       /*  1: 360kb in 720k or 1.2MB drive */
        { "D720",  9,1440, 0, 0},       /*  2: 720kb in 720k or 1.2MB drive */
@@ -658,7 +658,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
                        return -EINVAL;
                }
                type = minor2disktype[type].index;
-               UDT = &disk_type[type];
+               UDT = &atari_disk_type[type];
        }
 
        if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
@@ -1064,7 +1064,7 @@ static void fd_rwsec_done1(int status)
               searched for a non-existent sector! */
            !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {
                if (Probing) {
-                       if (SUDT > disk_type) {
+                       if (SUDT > atari_disk_type) {
                            if (SUDT[-1].blocks > ReqBlock) {
                                /* try another disk type */
                                SUDT--;
@@ -1082,7 +1082,7 @@ static void fd_rwsec_done1(int status)
                } else {        
 /* record not found, but not probing. Maybe stretch wrong ? Restart probing */
                        if (SUD.autoprobe) {
-                               SUDT = disk_type + StartDiskType[DriveType];
+                               SUDT = atari_disk_type + StartDiskType[DriveType];
                                set_capacity(unit[SelectedDrive].disk,
                                                        SUDT->blocks);
                                Probing = 1;
@@ -1421,7 +1421,7 @@ repeat:
        if (type == 0) {
                if (!UDT) {
                        Probing = 1;
-                       UDT = disk_type + StartDiskType[DriveType];
+                       UDT = atari_disk_type + StartDiskType[DriveType];
                        set_capacity(floppy->disk, UDT->blocks);
                        UD.autoprobe = 1;
                }
@@ -1439,7 +1439,7 @@ repeat:
                        goto repeat;
                }
                type = minor2disktype[type].index;
-               UDT = &disk_type[type];
+               UDT = &atari_disk_type[type];
                set_capacity(floppy->disk, UDT->blocks);
                UD.autoprobe = 0;
        }
@@ -1505,7 +1505,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
                        if (minor2disktype[type].drive_types > DriveType)
                                return -ENODEV;
                        type = minor2disktype[type].index;
-                       dtp = &disk_type[type];
+                       dtp = &atari_disk_type[type];
                        if (UD.flags & FTD_MSG)
                            printk (KERN_ERR "floppy%d: found dtp %p name %s!\n",
                                drive, dtp, dtp->name);
@@ -1576,7 +1576,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
                                continue;
                        }
                        setidx = minor2disktype[settype].index;
-                       dtp = &disk_type[setidx];
+                       dtp = &atari_disk_type[setidx];
 
                        /* found matching entry ?? */
                        if (   dtp->blocks  == setprm.size 
index 855ce8e..9715be3 100644 (file)
@@ -2630,12 +2630,14 @@ static void do_cciss_request(struct request_queue *q)
                        c->Request.CDB[8] = creq->nr_sectors & 0xff;
                        c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
                } else {
+                       u32 upper32 = upper_32_bits(start_blk);
+
                        c->Request.CDBLen = 16;
                        c->Request.CDB[1]= 0;
-                       c->Request.CDB[2]= (start_blk >> 56) & 0xff;    //MSB
-                       c->Request.CDB[3]= (start_blk >> 48) & 0xff;
-                       c->Request.CDB[4]= (start_blk >> 40) & 0xff;
-                       c->Request.CDB[5]= (start_blk >> 32) & 0xff;
+                       c->Request.CDB[2]= (upper32 >> 24) & 0xff;      //MSB
+                       c->Request.CDB[3]= (upper32 >> 16) & 0xff;
+                       c->Request.CDB[4]= (upper32 >>  8) & 0xff;
+                       c->Request.CDB[5]= upper32 & 0xff;
                        c->Request.CDB[6]= (start_blk >> 24) & 0xff;
                        c->Request.CDB[7]= (start_blk >> 16) & 0xff;
                        c->Request.CDB[8]= (start_blk >>  8) & 0xff;
index b8af22e..91ebb00 100644 (file)
@@ -973,6 +973,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
        lo->transfer = xfer->transfer;
        lo->ioctl = xfer->ioctl;
 
+       if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) !=
+            (info->lo_flags & LO_FLAGS_AUTOCLEAR))
+               lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
+
        lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
        lo->lo_init[0] = info->lo_init[0];
        lo->lo_init[1] = info->lo_init[1];
@@ -1331,6 +1335,10 @@ static int lo_release(struct inode *inode, struct file *file)
 
        mutex_lock(&lo->lo_ctl_mutex);
        --lo->lo_refcnt;
+
+       if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) && !lo->lo_refcnt)
+               loop_clr_fd(lo, inode->i_bdev);
+
        mutex_unlock(&lo->lo_ctl_mutex);
 
        return 0;
index 76096ca..8b9549a 100644 (file)
@@ -660,7 +660,7 @@ static int pt_open(struct inode *inode, struct file *file)
        pt_identify(tape);
 
        err = -ENODEV;
-       if (!tape->flags & PT_MEDIA)
+       if (!(tape->flags & PT_MEDIA))
                goto out;
 
        err = -EROFS;
index e9de171..674cd66 100644 (file)
@@ -2212,11 +2212,11 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
                return ret;
        }
 
-       if (!buf[6] & 0x40) {
+       if (!(buf[6] & 0x40)) {
                printk(DRIVER_NAME": Disc type is not CD-RW\n");
                return 1;
        }
-       if (!buf[6] & 0x4) {
+       if (!(buf[6] & 0x4)) {
                printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
                return 1;
        }
index 82f4eec..06e23be 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/backing-dev.h>
 #include <linux/blkpg.h>
 #include <linux/writeback.h>
+#include <linux/log2.h>
 
 #include <asm/uaccess.h>
 
@@ -450,7 +451,7 @@ static int __init rd_init(void)
        err = -ENOMEM;
 
        if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
-                       (rd_blocksize & (rd_blocksize-1))) {
+                       !is_power_of_2(rd_blocksize)) {
                printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
                       rd_blocksize);
                rd_blocksize = BLOCK_SIZE;
index 47e5b40..db259e6 100644 (file)
@@ -1206,25 +1206,26 @@ int check_for_audio_disc(struct cdrom_device_info * cdi,
        return 0;
 }
 
-/* Admittedly, the logic below could be performed in a nicer way. */
 int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        int opened_for_data;
 
-       cdinfo(CD_CLOSE, "entering cdrom_release\n"); 
+       cdinfo(CD_CLOSE, "entering cdrom_release\n");
 
        if (cdi->use_count > 0)
                cdi->use_count--;
-       if (cdi->use_count == 0)
+
+       if (cdi->use_count == 0) {
                cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
-       if (cdi->use_count == 0)
                cdrom_dvd_rw_close_write(cdi);
-       if (cdi->use_count == 0 &&
-           (cdo->capability & CDC_LOCK) && !keeplocked) {
-               cdinfo(CD_CLOSE, "Unlocking door!\n");
-               cdo->lock_door(cdi, 0);
+
+               if ((cdo->capability & CDC_LOCK) && !keeplocked) {
+                       cdinfo(CD_CLOSE, "Unlocking door!\n");
+                       cdo->lock_door(cdi, 0);
+               }
        }
+
        opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
                !(fp && fp->f_flags & O_NONBLOCK);
 
index 4666295..85bf9b2 100644 (file)
@@ -276,7 +276,7 @@ config N_HDLC
 
 config RISCOM8
        tristate "SDL RISCom/8 card support"
-       depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+       depends on SERIAL_NONSTANDARD
        help
          This is a driver for the SDL Communications RISCom/8 multiport card,
          which gives you many serial ports. You would need something like
@@ -765,7 +765,7 @@ config JS_RTC
 
 config SGI_DS1286
        tristate "SGI DS1286 RTC support"
-       depends on SGI_IP22
+       depends on SGI_HAS_DS1286
        help
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
index 480fae2..44160d5 100644 (file)
@@ -93,7 +93,7 @@ struct hvc_struct {
 };
 
 /* dynamic list of hvc_struct instances */
-static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs);
+static LIST_HEAD(hvc_structs);
 
 /*
  * Protect the list of hvc_struct instances from inserts and removals during
index 3402def..786d518 100644 (file)
@@ -306,7 +306,7 @@ struct hvcs_struct {
 /* Required to back map a kref to its containing object */
 #define from_kref(k) container_of(k, struct hvcs_struct, kref)
 
-static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs);
+static LIST_HEAD(hvcs_structs);
 static DEFINE_SPINLOCK(hvcs_structs_lock);
 
 static void hvcs_unthrottle(struct tty_struct *tty);
index 868e39f..f7feae4 100644 (file)
@@ -42,6 +42,8 @@ enum {
        VIA_STRFILT_ENABLE      = (1 << 14),
        VIA_RAWBITS_ENABLE      = (1 << 13),
        VIA_RNG_ENABLE          = (1 << 6),
+       VIA_NOISESRC1           = (1 << 8),
+       VIA_NOISESRC2           = (1 << 9),
        VIA_XSTORE_CNT_MASK     = 0x0F,
 
        VIA_RNG_CHUNK_8         = 0x00, /* 64 rand bits, 64 stored bits */
@@ -119,6 +121,7 @@ static int via_rng_data_read(struct hwrng *rng, u32 *data)
 
 static int via_rng_init(struct hwrng *rng)
 {
+       struct cpuinfo_x86 *c = &cpu_data(0);
        u32 lo, hi, old_lo;
 
        /* Control the RNG via MSR.  Tread lightly and pay very close
@@ -134,6 +137,17 @@ static int via_rng_init(struct hwrng *rng)
        lo &= ~VIA_XSTORE_CNT_MASK;
        lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
        lo |= VIA_RNG_ENABLE;
+       lo |= VIA_NOISESRC1;
+
+       /* Enable secondary noise source on CPUs where it is present. */
+
+       /* Nehemiah stepping 8 and higher */
+       if ((c->x86_model == 9) && (c->x86_mask > 7))
+               lo |= VIA_NOISESRC2;
+
+       /* Esther */
+       if (c->x86_model >= 10)
+               lo |= VIA_NOISESRC2;
 
        if (lo != old_lo)
                wrmsr(MSR_VIA_RNG, lo, hi);
index 30e5645..179223a 100644 (file)
@@ -439,6 +439,13 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
                },
        },
+       {       /* UK Inspiron 6400  */
+               .ident = "Dell Inspiron 3",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MM061"),
+               },
+       },
        { }
 };
 
index 932264a..86e6538 100644 (file)
@@ -46,8 +46,8 @@
 #include <asm/sn/sn0/hub.h>
 #include <asm/sn/sn_private.h>
 
-static int rtc_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, unsigned long arg);
+static long rtc_ioctl(struct file *filp, unsigned int cmd,
+                       unsigned long arg);
 
 static int rtc_read_proc(char *page, char **start, off_t off,
                          int count, int *eof, void *data);
@@ -75,8 +75,7 @@ static unsigned long epoch = 1970;    /* year corresponding to 0x00   */
 static const unsigned char days_in_mo[] =
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg)
+static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 
        struct rtc_time wtime;
@@ -197,7 +196,7 @@ static int rtc_release(struct inode *inode, struct file *file)
 
 static const struct file_operations rtc_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = rtc_ioctl,
+       .unlocked_ioctl = rtc_ioctl,
        .open           = rtc_open,
        .release        = rtc_release,
 };
index 5dc1265..32b2b22 100644 (file)
@@ -365,12 +365,12 @@ static struct device_driver ipmidriver = {
 };
 static DEFINE_MUTEX(ipmidriver_mutex);
 
-static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces);
+static LIST_HEAD(ipmi_interfaces);
 static DEFINE_MUTEX(ipmi_interfaces_mutex);
 
 /* List of watchers that want to know when smi's are added and
    deleted. */
-static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
+static LIST_HEAD(smi_watchers);
 static DEFINE_MUTEX(smi_watchers_mutex);
 
 
@@ -441,7 +441,7 @@ struct watcher_entry {
 int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
 {
        ipmi_smi_t intf;
-       struct list_head to_deliver = LIST_HEAD_INIT(to_deliver);
+       LIST_HEAD(to_deliver);
        struct watcher_entry *e, *e2;
 
        mutex_lock(&smi_watchers_mutex);
index 81674d7..60ac642 100644 (file)
@@ -312,7 +312,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf,
        if (copy_size > LP_BUFFER_SIZE)
                copy_size = LP_BUFFER_SIZE;
 
-       if (down_interruptible (&lp_table[minor].port_mutex))
+       if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
                return -EINTR;
 
        if (copy_from_user (kbuf, buf, copy_size)) {
@@ -399,7 +399,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf,
                lp_release_parport (&lp_table[minor]);
        }
 out_unlock:
-       up (&lp_table[minor].port_mutex);
+       mutex_unlock(&lp_table[minor].port_mutex);
 
        return retv;
 }
@@ -421,7 +421,7 @@ static ssize_t lp_read(struct file * file, char __user * buf,
        if (count > LP_BUFFER_SIZE)
                count = LP_BUFFER_SIZE;
 
-       if (down_interruptible (&lp_table[minor].port_mutex))
+       if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
                return -EINTR;
 
        lp_claim_parport_or_block (&lp_table[minor]);
@@ -479,7 +479,7 @@ static ssize_t lp_read(struct file * file, char __user * buf,
        if (retval > 0 && copy_to_user (buf, kbuf, retval))
                retval = -EFAULT;
 
-       up (&lp_table[minor].port_mutex);
+       mutex_unlock(&lp_table[minor].port_mutex);
 
        return retval;
 }
@@ -888,7 +888,7 @@ static int __init lp_init (void)
                lp_table[i].last_error = 0;
                init_waitqueue_head (&lp_table[i].waitq);
                init_waitqueue_head (&lp_table[i].dataq);
-               init_MUTEX (&lp_table[i].port_mutex);
+               mutex_init(&lp_table[i].port_mutex);
                lp_table[i].timeout = 10 * HZ;
        }
 
index fd0abef..4742078 100644 (file)
@@ -37,7 +37,6 @@
 
 
 #include <linux/module.h>
-#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
index 081c84c..bf1bee4 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
index 596c717..90c3969 100644 (file)
@@ -695,17 +695,16 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
                return;
        }
        
-       if (tty->stopped && !tty->flow_stopped &&
-           I_IXON(tty) && I_IXANY(tty)) {
-               start_tty(tty);
-               return;
-       }
-       
        if (I_ISTRIP(tty))
                c &= 0x7f;
        if (I_IUCLC(tty) && L_IEXTEN(tty))
                c=tolower(c);
 
+       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
+           ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
+            c == INTR_CHAR(tty) || c == QUIT_CHAR(tty)))
+               start_tty(tty);
+
        if (tty->closing) {
                if (I_IXON(tty)) {
                        if (c == START_CHAR(tty))
@@ -769,7 +768,21 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
                signal = SIGTSTP;
                if (c == SUSP_CHAR(tty)) {
 send_signal:
-                       isig(signal, tty, 0);
+                       /*
+                        * Echo character, and then send the signal.
+                        * Note that we do not use isig() here because we want
+                        * the order to be:
+                        * 1) flush, 2) echo, 3) signal
+                        */
+                       if (!L_NOFLSH(tty)) {
+                               n_tty_flush_buffer(tty);
+                               if (tty->driver->flush_buffer)
+                                       tty->driver->flush_buffer(tty);
+                       }
+                       if (L_ECHO(tty))
+                               echo_char(c, tty);
+                       if (tty->pgrp)
+                               kill_pgrp(tty->pgrp, signal, 1);
                        return;
                }
        }
index 8caff0c..279ff50 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/ioctl.h>
+#include <linux/synclink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -87,8 +88,6 @@
 
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 static MGSL_PARAMS default_params = {
        MGSL_MODE_HDLC,                 /* unsigned long mode */
        0,                              /* unsigned char loopback; */
index c511a83..f43c89f 100644 (file)
@@ -1039,6 +1039,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
                p += bytes;
 
                add_entropy_words(r, buf, (bytes + 3) / 4);
+               cond_resched();
        }
 
        return 0;
index 102ece4..d130b87 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/tty_flip.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
@@ -81,6 +82,8 @@
 
 static struct tty_driver *riscom_driver;
 
+static DEFINE_SPINLOCK(riscom_lock);
+
 static struct riscom_board rc_board[RC_NBOARD] =  {
        {
                .base   = RC_IOBASE1,
@@ -217,13 +220,14 @@ static void __init rc_init_CD180(struct riscom_board const * bp)
 {
        unsigned long flags;
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        rc_out(bp, RC_CTOUT, 0);                   /* Clear timeout             */
        rc_wait_CCR(bp);                           /* Wait for CCR ready        */
        rc_out(bp, CD180_CCR, CCR_HARDRESET);      /* Reset CD180 chip          */
-       sti();
+       spin_unlock_irqrestore(&riscom_lock, flags);
        msleep(50);                                /* Delay 0.05 sec            */
-       cli();
+       spin_lock_irqsave(&riscom_lock, flags);
        rc_out(bp, CD180_GIVR, RC_ID);             /* Set ID for this chip      */
        rc_out(bp, CD180_GICR, 0);                 /* Clear all bits            */
        rc_out(bp, CD180_PILR1, RC_ACK_MINT);      /* Prio for modem intr       */
@@ -234,7 +238,7 @@ static void __init rc_init_CD180(struct riscom_board const * bp)
        rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
        rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
        
-       restore_flags(flags);
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 /* Main probing routine, also sets irq. */
@@ -812,9 +816,9 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
                }
                port->xmit_buf = (unsigned char *) tmp;
        }
-               
-       save_flags(flags); cli();
-               
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (port->tty) 
                clear_bit(TTY_IO_ERROR, &port->tty->flags);
                
@@ -825,7 +829,7 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
        rc_change_speed(bp, port);
        port->flags |= ASYNC_INITIALIZED;
                
-       restore_flags(flags);
+       spin_unlock_irqrestore(&riscom_lock, flags);
        return 0;
 }
 
@@ -901,6 +905,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        int    retval;
        int    do_clocal = 0;
        int    CD;
+       unsigned long flags;
 
        /*
         * If the device is in the middle of being closed, then block
@@ -936,19 +941,26 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
         */
        retval = 0;
        add_wait_queue(&port->open_wait, &wait);
-       cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (!tty_hung_up_p(filp))
                port->count--;
-       sti();
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
+
        port->blocked_open++;
        while (1) {
-               cli();
+               spin_lock_irqsave(&riscom_lock, flags);
+
                rc_out(bp, CD180_CAR, port_No(port));
                CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
                rc_out(bp, CD180_MSVR, MSVR_RTS);
                bp->DTR &= ~(1u << port_No(port));
                rc_out(bp, RC_DTR, bp->DTR);
-               sti();
+
+               spin_unlock_irqrestore(&riscom_lock, flags);
+
                set_current_state(TASK_INTERRUPTIBLE);
                if (tty_hung_up_p(filp) ||
                    !(port->flags & ASYNC_INITIALIZED)) {
@@ -1020,8 +1032,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
        
        if (!port || rc_paranoia_check(port, tty->name, "close"))
                return;
-       
-       save_flags(flags); cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (tty_hung_up_p(filp))
                goto out;
        
@@ -1088,7 +1101,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
        }
        port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
        wake_up_interruptible(&port->close_wait);
-out:   restore_flags(flags);
+
+out:
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static int rc_write(struct tty_struct * tty, 
@@ -1107,34 +1122,33 @@ static int rc_write(struct tty_struct * tty,
        if (!tty || !port->xmit_buf)
                return 0;
 
-       save_flags(flags);
        while (1) {
-               cli();          
+               spin_lock_irqsave(&riscom_lock, flags);
+
                c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
                                          SERIAL_XMIT_SIZE - port->xmit_head));
-               if (c <= 0) {
-                       restore_flags(flags);
-                       break;
-               }
+               if (c <= 0)
+                       break;  /* lock continues to be held */
 
                memcpy(port->xmit_buf + port->xmit_head, buf, c);
                port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
                port->xmit_cnt += c;
-               restore_flags(flags);
+
+               spin_unlock_irqrestore(&riscom_lock, flags);
 
                buf += c;
                count -= c;
                total += c;
        }
 
-       cli();
        if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
            !(port->IER & IER_TXRDY)) {
                port->IER |= IER_TXRDY;
                rc_out(bp, CD180_CAR, port_No(port));
                rc_out(bp, CD180_IER, port->IER);
        }
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 
        return total;
 }
@@ -1150,7 +1164,7 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch)
        if (!tty || !port->xmit_buf)
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
        
        if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
                goto out;
@@ -1158,7 +1172,9 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch)
        port->xmit_buf[port->xmit_head++] = ch;
        port->xmit_head &= SERIAL_XMIT_SIZE - 1;
        port->xmit_cnt++;
-out:   restore_flags(flags);
+
+out:
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_flush_chars(struct tty_struct * tty)
@@ -1173,11 +1189,13 @@ static void rc_flush_chars(struct tty_struct * tty)
            !port->xmit_buf)
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->IER |= IER_TXRDY;
        rc_out(port_Board(port), CD180_CAR, port_No(port));
        rc_out(port_Board(port), CD180_IER, port->IER);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static int rc_write_room(struct tty_struct * tty)
@@ -1212,9 +1230,11 @@ static void rc_flush_buffer(struct tty_struct *tty)
        if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
        
        tty_wakeup(tty);
 }
@@ -1231,11 +1251,15 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file)
                return -ENODEV;
 
        bp = port_Board(port);
-       save_flags(flags); cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        rc_out(bp, CD180_CAR, port_No(port));
        status = rc_in(bp, CD180_MSVR);
        result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
+
        result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)
                | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
                | ((status & MSVR_CD)  ? TIOCM_CAR : 0)
@@ -1256,7 +1280,8 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
 
        bp = port_Board(port);
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (set & TIOCM_RTS)
                port->MSVR |= MSVR_RTS;
        if (set & TIOCM_DTR)
@@ -1270,7 +1295,9 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
        rc_out(bp, CD180_CAR, port_No(port));
        rc_out(bp, CD180_MSVR, port->MSVR);
        rc_out(bp, RC_DTR, bp->DTR);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
+
        return 0;
 }
 
@@ -1279,7 +1306,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
        struct riscom_board *bp = port_Board(port);
        unsigned long flags;
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->break_length = RISCOM_TPS / HZ * length;
        port->COR2 |= COR2_ETC;
        port->IER  |= IER_TXRDY;
@@ -1289,7 +1317,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length
        rc_wait_CCR(bp);
        rc_out(bp, CD180_CCR, CCR_CORCHG2);
        rc_wait_CCR(bp);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static inline int rc_set_serial_info(struct riscom_port * port,
@@ -1298,7 +1327,6 @@ static inline int rc_set_serial_info(struct riscom_port * port,
        struct serial_struct tmp;
        struct riscom_board *bp = port_Board(port);
        int change_speed;
-       unsigned long flags;
        
        if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
                return -EFAULT;
@@ -1332,9 +1360,11 @@ static inline int rc_set_serial_info(struct riscom_port * port,
                port->closing_wait = tmp.closing_wait;
        }
        if (change_speed)  {
-               save_flags(flags); cli();
+               unsigned long flags;
+
+               spin_lock_irqsave(&riscom_lock, flags);
                rc_change_speed(bp, port);
-               restore_flags(flags);
+               spin_unlock_irqrestore(&riscom_lock, flags);
        }
        return 0;
 }
@@ -1414,17 +1444,19 @@ static void rc_throttle(struct tty_struct * tty)
                return;
        
        bp = port_Board(port);
-       
-       save_flags(flags); cli();
+
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->MSVR &= ~MSVR_RTS;
        rc_out(bp, CD180_CAR, port_No(port));
-       if (I_IXOFF(tty))  {
+       if (I_IXOFF(tty)) {
                rc_wait_CCR(bp);
                rc_out(bp, CD180_CCR, CCR_SSCH2);
                rc_wait_CCR(bp);
        }
        rc_out(bp, CD180_MSVR, port->MSVR);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_unthrottle(struct tty_struct * tty)
@@ -1438,7 +1470,8 @@ static void rc_unthrottle(struct tty_struct * tty)
        
        bp = port_Board(port);
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->MSVR |= MSVR_RTS;
        rc_out(bp, CD180_CAR, port_No(port));
        if (I_IXOFF(tty))  {
@@ -1447,7 +1480,8 @@ static void rc_unthrottle(struct tty_struct * tty)
                rc_wait_CCR(bp);
        }
        rc_out(bp, CD180_MSVR, port->MSVR);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_stop(struct tty_struct * tty)
@@ -1461,11 +1495,13 @@ static void rc_stop(struct tty_struct * tty)
        
        bp = port_Board(port);
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        port->IER &= ~IER_TXRDY;
        rc_out(bp, CD180_CAR, port_No(port));
        rc_out(bp, CD180_IER, port->IER);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 static void rc_start(struct tty_struct * tty)
@@ -1479,13 +1515,15 @@ static void rc_start(struct tty_struct * tty)
        
        bp = port_Board(port);
        
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY))  {
                port->IER |= IER_TXRDY;
                rc_out(bp, CD180_CAR, port_No(port));
                rc_out(bp, CD180_IER, port->IER);
        }
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 /*
@@ -1537,9 +1575,9 @@ static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termio
            tty->termios->c_iflag == old_termios->c_iflag)
                return;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&riscom_lock, flags);
        rc_change_speed(port_Board(port), port);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&riscom_lock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
            !(tty->termios->c_cflag & CRTSCTS)) {
@@ -1627,11 +1665,12 @@ static void rc_release_drivers(void)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&riscom_lock, flags);
+
        tty_unregister_driver(riscom_driver);
        put_tty_driver(riscom_driver);
-       restore_flags(flags);
+
+       spin_unlock_irqrestore(&riscom_lock, flags);
 }
 
 #ifndef MODULE
index 3c86914..4ba3aec 100644 (file)
@@ -653,7 +653,7 @@ static void a2232_init_portstructs(void)
                port->gs.closing_wait = 30 * HZ;
                port->gs.rd = &a2232_real_driver;
 #ifdef NEW_WRITE_LOCKING
-               init_MUTEX(&(port->gs.port_write_mutex));
+               mutex_init(&(port->gs.port_write_mutex));
 #endif
                init_waitqueue_head(&port->gs.open_wait);
                init_waitqueue_head(&port->gs.close_wait);
index d010ed9..ddc74d1 100644 (file)
@@ -85,6 +85,7 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/ioctl.h>
+#include <linux/synclink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 #define RCLRVALUE 0xffff
 
 static MGSL_PARAMS default_params = {
index 64e835f..1f954ac 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
+#include <linux/synclink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -81,8 +82,6 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))
 #define SYNCLINK_GENERIC_HDLC 1
 #else
@@ -2040,37 +2039,41 @@ static void bh_transmit(struct slgt_info *info)
                tty_wakeup(tty);
 }
 
-static void dsr_change(struct slgt_info *info)
+static void dsr_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT3) {
+               info->signals |= SerialSignal_DSR;
+               info->input_signal_events.dsr_up++;
+       } else {
+               info->signals &= ~SerialSignal_DSR;
+               info->input_signal_events.dsr_down++;
+       }
        DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DSR);
                return;
        }
        info->icount.dsr++;
-       if (info->signals & SerialSignal_DSR)
-               info->input_signal_events.dsr_up++;
-       else
-               info->input_signal_events.dsr_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
 }
 
-static void cts_change(struct slgt_info *info)
+static void cts_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT2) {
+               info->signals |= SerialSignal_CTS;
+               info->input_signal_events.cts_up++;
+       } else {
+               info->signals &= ~SerialSignal_CTS;
+               info->input_signal_events.cts_down++;
+       }
        DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_CTS);
                return;
        }
        info->icount.cts++;
-       if (info->signals & SerialSignal_CTS)
-               info->input_signal_events.cts_up++;
-       else
-               info->input_signal_events.cts_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -2091,20 +2094,21 @@ static void cts_change(struct slgt_info *info)
        }
 }
 
-static void dcd_change(struct slgt_info *info)
+static void dcd_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT1) {
+               info->signals |= SerialSignal_DCD;
+               info->input_signal_events.dcd_up++;
+       } else {
+               info->signals &= ~SerialSignal_DCD;
+               info->input_signal_events.dcd_down++;
+       }
        DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DCD);
                return;
        }
        info->icount.dcd++;
-       if (info->signals & SerialSignal_DCD) {
-               info->input_signal_events.dcd_up++;
-       } else {
-               info->input_signal_events.dcd_down++;
-       }
 #if SYNCLINK_GENERIC_HDLC
        if (info->netcount) {
                if (info->signals & SerialSignal_DCD)
@@ -2127,20 +2131,21 @@ static void dcd_change(struct slgt_info *info)
        }
 }
 
-static void ri_change(struct slgt_info *info)
+static void ri_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT0) {
+               info->signals |= SerialSignal_RI;
+               info->input_signal_events.ri_up++;
+       } else {
+               info->signals &= ~SerialSignal_RI;
+               info->input_signal_events.ri_down++;
+       }
        DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_RI);
                return;
        }
-       info->icount.dcd++;
-       if (info->signals & SerialSignal_RI) {
-               info->input_signal_events.ri_up++;
-       } else {
-               info->input_signal_events.ri_down++;
-       }
+       info->icount.rng++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -2191,13 +2196,13 @@ static void isr_serial(struct slgt_info *info)
        }
 
        if (status & IRQ_DSR)
-               dsr_change(info);
+               dsr_change(info, status);
        if (status & IRQ_CTS)
-               cts_change(info);
+               cts_change(info, status);
        if (status & IRQ_DCD)
-               dcd_change(info);
+               dcd_change(info, status);
        if (status & IRQ_RI)
-               ri_change(info);
+               ri_change(info, status);
 }
 
 static void isr_rdma(struct slgt_info *info)
index c63013b..f3e7807 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/termios.h>
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
+#include <linux/synclink.h>
 
 #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE))
 #define SYNCLINK_GENERIC_HDLC 1
@@ -80,8 +81,6 @@
 
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 static MGSL_PARAMS default_params = {
        MGSL_MODE_HDLC,                 /* unsigned long mode */
        0,                              /* unsigned char loopback; */
index c88424a..a5d8bcb 100644 (file)
@@ -1031,18 +1031,13 @@ void tpm_remove_hardware(struct device *dev)
 
        spin_unlock(&driver_lock);
 
-       dev_set_drvdata(dev, NULL);
        misc_deregister(&chip->vendor.miscdev);
-       kfree(chip->vendor.miscdev.name);
 
        sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
        tpm_bios_log_teardown(chip->bios_dir);
 
-       clear_bit(chip->dev_num, dev_mask);
-
-       kfree(chip);
-
-       put_device(dev);
+       /* write it this way to be explicit (chip->dev == dev) */
+       put_device(chip->dev);
 }
 EXPORT_SYMBOL_GPL(tpm_remove_hardware);
 
@@ -1082,6 +1077,26 @@ int tpm_pm_resume(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(tpm_pm_resume);
 
+/*
+ * Once all references to platform device are down to 0,
+ * release all allocated structures.
+ * In case vendor provided release function,
+ * call it too.
+ */
+static void tpm_dev_release(struct device *dev)
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+
+       if (chip->vendor.release)
+               chip->vendor.release(dev);
+
+       chip->release(dev);
+
+       clear_bit(chip->dev_num, dev_mask);
+       kfree(chip->vendor.miscdev.name);
+       kfree(chip);
+}
+
 /*
  * Called from tpm_<specific>.c probe function only for devices 
  * the driver has determined it should claim.  Prior to calling
@@ -1136,23 +1151,21 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
 
        chip->vendor.miscdev.parent = dev;
        chip->dev = get_device(dev);
+       chip->release = dev->release;
+       dev->release = tpm_dev_release;
+       dev_set_drvdata(dev, chip);
 
        if (misc_register(&chip->vendor.miscdev)) {
                dev_err(chip->dev,
                        "unable to misc_register %s, minor %d\n",
                        chip->vendor.miscdev.name,
                        chip->vendor.miscdev.minor);
-               put_device(dev);
-               clear_bit(chip->dev_num, dev_mask);
-               kfree(chip);
-               kfree(devname);
+               put_device(chip->dev);
                return NULL;
        }
 
        spin_lock(&driver_lock);
 
-       dev_set_drvdata(dev, chip);
-
        list_add(&chip->list, &tpm_chip_list);
 
        spin_unlock(&driver_lock);
@@ -1160,10 +1173,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
        if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
                list_del(&chip->list);
                misc_deregister(&chip->vendor.miscdev);
-               put_device(dev);
-               clear_bit(chip->dev_num, dev_mask);
-               kfree(chip);
-               kfree(devname);
+               put_device(chip->dev);
                return NULL;
        }
 
index d15ccdd..e885148 100644 (file)
@@ -74,6 +74,7 @@ struct tpm_vendor_specific {
        int (*send) (struct tpm_chip *, u8 *, size_t);
        void (*cancel) (struct tpm_chip *);
        u8 (*status) (struct tpm_chip *);
+       void (*release) (struct device *);
        struct miscdevice miscdev;
        struct attribute_group *attr_group;
        struct list_head list;
@@ -106,6 +107,7 @@ struct tpm_chip {
        struct dentry **bios_dir;
 
        struct list_head list;
+       void (*release) (struct device *);
 };
 
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
index 967002a..726ee8a 100644 (file)
@@ -611,7 +611,7 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
        }
 }
 
-static struct pnp_driver tpm_inf_pnp = {
+static struct pnp_driver tpm_inf_pnp_driver = {
        .name = "tpm_inf_pnp",
        .driver = {
                .owner = THIS_MODULE,
@@ -625,12 +625,12 @@ static struct pnp_driver tpm_inf_pnp = {
 
 static int __init init_inf(void)
 {
-       return pnp_register_driver(&tpm_inf_pnp);
+       return pnp_register_driver(&tpm_inf_pnp_driver);
 }
 
 static void __exit cleanup_inf(void)
 {
-       pnp_unregister_driver(&tpm_inf_pnp);
+       pnp_unregister_driver(&tpm_inf_pnp_driver);
 }
 
 module_init(init_inf);
index f36fecd..79c86c4 100644 (file)
@@ -138,7 +138,7 @@ EXPORT_SYMBOL(tty_mutex);
 extern struct tty_driver *ptm_driver;  /* Unix98 pty masters; for /dev/ptmx */
 extern int pty_limit;          /* Config limit on Unix98 ptys */
 static DEFINE_IDR(allocated_ptys);
-static DECLARE_MUTEX(allocated_ptys_lock);
+static DEFINE_MUTEX(allocated_ptys_lock);
 static int ptmx_open(struct inode *, struct file *);
 #endif
 
@@ -2571,9 +2571,9 @@ static void release_dev(struct file * filp)
 #ifdef CONFIG_UNIX98_PTYS
        /* Make this pty number available for reallocation */
        if (devpts) {
-               down(&allocated_ptys_lock);
+               mutex_lock(&allocated_ptys_lock);
                idr_remove(&allocated_ptys, idx);
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
        }
 #endif
 
@@ -2737,24 +2737,24 @@ static int ptmx_open(struct inode * inode, struct file * filp)
        nonseekable_open(inode, filp);
 
        /* find a device that is not in use. */
-       down(&allocated_ptys_lock);
+       mutex_lock(&allocated_ptys_lock);
        if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
                return -ENOMEM;
        }
        idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
        if (idr_ret < 0) {
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
                if (idr_ret == -EAGAIN)
                        return -ENOMEM;
                return -EIO;
        }
        if (index >= pty_limit) {
                idr_remove(&allocated_ptys, index);
-               up(&allocated_ptys_lock);
+               mutex_unlock(&allocated_ptys_lock);
                return -EIO;
        }
-       up(&allocated_ptys_lock);
+       mutex_unlock(&allocated_ptys_lock);
 
        mutex_lock(&tty_mutex);
        retval = init_dev(ptm_driver, index, &tty);
@@ -2781,9 +2781,9 @@ out1:
        release_dev(filp);
        return retval;
 out:
-       down(&allocated_ptys_lock);
+       mutex_lock(&allocated_ptys_lock);
        idr_remove(&allocated_ptys, index);
-       up(&allocated_ptys_lock);
+       mutex_unlock(&allocated_ptys_lock);
        return retval;
 }
 #endif
@@ -3721,7 +3721,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
        tty->buf.head = tty->buf.tail = NULL;
        tty_buffer_init(tty);
        INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
-       init_MUTEX(&tty->buf.pty_sem);
        mutex_init(&tty->termios_mutex);
        init_waitqueue_head(&tty->write_wait);
        init_waitqueue_head(&tty->read_wait);
@@ -4048,10 +4047,6 @@ void __init console_init(void)
        }
 }
 
-#ifdef CONFIG_VT
-extern int vty_init(void);
-#endif
-
 static int __init tty_class_init(void)
 {
        tty_class = class_create(THIS_MODULE, "tty");
index 7a5badf..367be91 100644 (file)
@@ -2400,13 +2400,15 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
 {
        struct vc_data *vc = vc_cons[fg_console].d;
        unsigned char c;
-       static unsigned long printing;
+       static DEFINE_SPINLOCK(printing_lock);
        const ushort *start;
        ushort cnt = 0;
        ushort myx;
 
        /* console busy or not yet initialized */
-       if (!printable || test_and_set_bit(0, &printing))
+       if (!printable)
+               return;
+       if (!spin_trylock(&printing_lock))
                return;
 
        if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
@@ -2481,7 +2483,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
        notify_update(vc);
 
 quit:
-       clear_bit(0, &printing);
+       spin_unlock(&printing_lock);
 }
 
 static struct tty_driver *vt_console_device(struct console *c, int *index)
index c46b7c2..a703def 100644 (file)
@@ -5,6 +5,7 @@
 menuconfig DMADEVICES
        bool "DMA Engine support"
        depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
+       depends on !HIGHMEM64G
        help
          DMA engines can do asynchronous data transfers without
          involving the host CPU.  Currently, this framework can be
index bcf52df..2996523 100644 (file)
@@ -473,20 +473,22 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
 {
        struct dma_device *dev = chan->device;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int cpu;
 
-       tx = dev->device_prep_dma_memcpy(chan, len, 0);
-       if (!tx)
+       dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
+       dma_dest = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
+       tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+       if (!tx) {
+               dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
+               dma_unmap_single(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
                return -ENOMEM;
+       }
 
        tx->ack = 1;
        tx->callback = NULL;
-       addr = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        cookie = tx->tx_submit(tx);
 
        cpu = get_cpu();
@@ -517,20 +519,22 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
 {
        struct dma_device *dev = chan->device;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int cpu;
 
-       tx = dev->device_prep_dma_memcpy(chan, len, 0);
-       if (!tx)
+       dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
+       dma_dest = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
+       tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+       if (!tx) {
+               dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
+               dma_unmap_page(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
                return -ENOMEM;
+       }
 
        tx->ack = 1;
        tx->callback = NULL;
-       addr = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        cookie = tx->tx_submit(tx);
 
        cpu = get_cpu();
@@ -563,20 +567,23 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
 {
        struct dma_device *dev = chan->device;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int cpu;
 
-       tx = dev->device_prep_dma_memcpy(chan, len, 0);
-       if (!tx)
+       dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
+       dma_dest = dma_map_page(dev->dev, dest_pg, dest_off, len,
+                               DMA_FROM_DEVICE);
+       tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0);
+
+       if (!tx) {
+               dma_unmap_page(dev->dev, dma_src, len, DMA_TO_DEVICE);
+               dma_unmap_page(dev->dev, dma_dest, len, DMA_FROM_DEVICE);
                return -ENOMEM;
+       }
 
        tx->ack = 1;
        tx->callback = NULL;
-       addr = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_page(dev->dev, dest_pg, dest_off, len, DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        cookie = tx->tx_submit(tx);
 
        cpu = get_cpu();
index 45e7b46..dff38ac 100644 (file)
@@ -159,20 +159,6 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
        return device->common.chancnt;
 }
 
-static void ioat_set_src(dma_addr_t addr,
-                        struct dma_async_tx_descriptor *tx,
-                        int index)
-{
-       tx_to_ioat_desc(tx)->src = addr;
-}
-
-static void ioat_set_dest(dma_addr_t addr,
-                         struct dma_async_tx_descriptor *tx,
-                         int index)
-{
-       tx_to_ioat_desc(tx)->dst = addr;
-}
-
 /**
  * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended
  *                                 descriptors to hw
@@ -415,8 +401,6 @@ static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
 
        memset(desc, 0, sizeof(*desc));
        dma_async_tx_descriptor_init(&desc_sw->async_tx, &ioat_chan->common);
-       desc_sw->async_tx.tx_set_src = ioat_set_src;
-       desc_sw->async_tx.tx_set_dest = ioat_set_dest;
        switch (ioat_chan->device->version) {
        case IOAT_VER_1_2:
                desc_sw->async_tx.tx_submit = ioat1_tx_submit;
@@ -714,8 +698,10 @@ static struct ioat_desc_sw *ioat_dma_get_next_descriptor(
 
 static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
                                                struct dma_chan *chan,
+                                               dma_addr_t dma_dest,
+                                               dma_addr_t dma_src,
                                                size_t len,
-                                               int int_en)
+                                               unsigned long flags)
 {
        struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
        struct ioat_desc_sw *new;
@@ -726,6 +712,8 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
 
        if (new) {
                new->len = len;
+               new->dst = dma_dest;
+               new->src = dma_src;
                return &new->async_tx;
        } else
                return NULL;
@@ -733,8 +721,10 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
 
 static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
                                                struct dma_chan *chan,
+                                               dma_addr_t dma_dest,
+                                               dma_addr_t dma_src,
                                                size_t len,
-                                               int int_en)
+                                               unsigned long flags)
 {
        struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
        struct ioat_desc_sw *new;
@@ -749,6 +739,8 @@ static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
 
        if (new) {
                new->len = len;
+               new->dst = dma_dest;
+               new->src = dma_src;
                return &new->async_tx;
        } else
                return NULL;
@@ -1045,7 +1037,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
        u8 *dest;
        struct dma_chan *dma_chan;
        struct dma_async_tx_descriptor *tx;
-       dma_addr_t addr;
+       dma_addr_t dma_dest, dma_src;
        dma_cookie_t cookie;
        int err = 0;
 
@@ -1073,7 +1065,12 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
                goto out;
        }
 
-       tx = device->common.device_prep_dma_memcpy(dma_chan, IOAT_TEST_SIZE, 0);
+       dma_src = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
+                                DMA_TO_DEVICE);
+       dma_dest = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
+                                 DMA_FROM_DEVICE);
+       tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src,
+                                                  IOAT_TEST_SIZE, 0);
        if (!tx) {
                dev_err(&device->pdev->dev,
                        "Self-test prep failed, disabling\n");
@@ -1082,12 +1079,6 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
        }
 
        async_tx_ack(tx);
-       addr = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
-                             DMA_TO_DEVICE);
-       tx->tx_set_src(addr, tx, 0);
-       addr = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
-                             DMA_FROM_DEVICE);
-       tx->tx_set_dest(addr, tx, 0);
        tx->callback = ioat_dma_test_callback;
        tx->callback_param = (void *)0x8086;
        cookie = tx->tx_submit(tx);
index e5c62b7..3986d54 100644 (file)
@@ -284,7 +284,7 @@ iop_adma_alloc_slots(struct iop_adma_chan *iop_chan, int num_slots,
                        int slots_per_op)
 {
        struct iop_adma_desc_slot *iter, *_iter, *alloc_start = NULL;
-       struct list_head chain = LIST_HEAD_INIT(chain);
+       LIST_HEAD(chain);
        int slots_found, retry = 0;
 
        /* start search from the last allocated descrtiptor
@@ -443,17 +443,6 @@ iop_adma_tx_submit(struct dma_async_tx_descriptor *tx)
        return cookie;
 }
 
-static void
-iop_adma_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
-       int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_chan *iop_chan = to_iop_adma_chan(tx->chan);
-
-       /* to do: support transfers lengths > IOP_ADMA_MAX_BYTE_COUNT */
-       iop_desc_set_dest_addr(sw_desc->group_head, iop_chan, addr);
-}
-
 static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan);
 static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan);
 
@@ -486,7 +475,6 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
 
                dma_async_tx_descriptor_init(&slot->async_tx, chan);
                slot->async_tx.tx_submit = iop_adma_tx_submit;
-               slot->async_tx.tx_set_dest = iop_adma_set_dest;
                INIT_LIST_HEAD(&slot->chain_node);
                INIT_LIST_HEAD(&slot->slot_node);
                INIT_LIST_HEAD(&slot->async_tx.tx_list);
@@ -547,18 +535,9 @@ iop_adma_prep_dma_interrupt(struct dma_chan *chan)
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static void
-iop_adma_memcpy_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
-       int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
-       iop_desc_set_memcpy_src_addr(grp_start, addr);
-}
-
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
+iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
+                        dma_addr_t dma_src, size_t len, unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -576,11 +555,12 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_memcpy(grp_start, int_en);
+               iop_desc_init_memcpy(grp_start, flags);
                iop_desc_set_byte_count(grp_start, iop_chan, len);
+               iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
+               iop_desc_set_memcpy_src_addr(grp_start, dma_src);
                sw_desc->unmap_src_cnt = 1;
                sw_desc->unmap_len = len;
-               sw_desc->async_tx.tx_set_src = iop_adma_memcpy_set_src;
        }
        spin_unlock_bh(&iop_chan->lock);
 
@@ -588,8 +568,8 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
 }
 
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
-       int int_en)
+iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest,
+                        int value, size_t len, unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -607,9 +587,10 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_memset(grp_start, int_en);
+               iop_desc_init_memset(grp_start, flags);
                iop_desc_set_byte_count(grp_start, iop_chan, len);
                iop_desc_set_block_fill_val(grp_start, value);
+               iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
                sw_desc->unmap_src_cnt = 1;
                sw_desc->unmap_len = len;
        }
@@ -618,19 +599,10 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static void
-iop_adma_xor_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
-       int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
-       iop_desc_set_xor_src_addr(grp_start, index, addr);
-}
-
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_xor(struct dma_chan *chan, unsigned int src_cnt, size_t len,
-       int int_en)
+iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
+                     dma_addr_t *dma_src, unsigned int src_cnt, size_t len,
+                     unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -641,39 +613,32 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, unsigned int src_cnt, size_t len,
        BUG_ON(unlikely(len > IOP_ADMA_XOR_MAX_BYTE_COUNT));
 
        dev_dbg(iop_chan->device->common.dev,
-               "%s src_cnt: %d len: %u int_en: %d\n",
-               __FUNCTION__, src_cnt, len, int_en);
+               "%s src_cnt: %d len: %u flags: %lx\n",
+               __FUNCTION__, src_cnt, len, flags);
 
        spin_lock_bh(&iop_chan->lock);
        slot_cnt = iop_chan_xor_slot_count(len, src_cnt, &slots_per_op);
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_xor(grp_start, src_cnt, int_en);
+               iop_desc_init_xor(grp_start, src_cnt, flags);
                iop_desc_set_byte_count(grp_start, iop_chan, len);
+               iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
                sw_desc->unmap_src_cnt = src_cnt;
                sw_desc->unmap_len = len;
-               sw_desc->async_tx.tx_set_src = iop_adma_xor_set_src;
+               while (src_cnt--)
+                       iop_desc_set_xor_src_addr(grp_start, src_cnt,
+                                                 dma_src[src_cnt]);
        }
        spin_unlock_bh(&iop_chan->lock);
 
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static void
-iop_adma_xor_zero_sum_set_src(dma_addr_t addr,
-                               struct dma_async_tx_descriptor *tx,
-                               int index)
-{
-       struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
-       struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
-
-       iop_desc_set_zero_sum_src_addr(grp_start, index, addr);
-}
-
 static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_zero_sum(struct dma_chan *chan, unsigned int src_cnt,
-       size_t len, u32 *result, int int_en)
+iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src,
+                          unsigned int src_cnt, size_t len, u32 *result,
+                          unsigned long flags)
 {
        struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
        struct iop_adma_desc_slot *sw_desc, *grp_start;
@@ -690,14 +655,16 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, unsigned int src_cnt,
        sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
        if (sw_desc) {
                grp_start = sw_desc->group_head;
-               iop_desc_init_zero_sum(grp_start, src_cnt, int_en);
+               iop_desc_init_zero_sum(grp_start, src_cnt, flags);
                iop_desc_set_zero_sum_byte_count(grp_start, len);
                grp_start->xor_check_result = result;
                pr_debug("\t%s: grp_start->xor_check_result: %p\n",
                        __FUNCTION__, grp_start->xor_check_result);
                sw_desc->unmap_src_cnt = src_cnt;
                sw_desc->unmap_len = len;
-               sw_desc->async_tx.tx_set_src = iop_adma_xor_zero_sum_set_src;
+               while (src_cnt--)
+                       iop_desc_set_zero_sum_src_addr(grp_start, src_cnt,
+                                                      dma_src[src_cnt]);
        }
        spin_unlock_bh(&iop_chan->lock);
 
@@ -882,13 +849,12 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device)
                goto out;
        }
 
-       tx = iop_adma_prep_dma_memcpy(dma_chan, IOP_ADMA_TEST_SIZE, 1);
        dest_dma = dma_map_single(dma_chan->device->dev, dest,
                                IOP_ADMA_TEST_SIZE, DMA_FROM_DEVICE);
-       iop_adma_set_dest(dest_dma, tx, 0);
        src_dma = dma_map_single(dma_chan->device->dev, src,
                                IOP_ADMA_TEST_SIZE, DMA_TO_DEVICE);
-       iop_adma_memcpy_set_src(src_dma, tx, 0);
+       tx = iop_adma_prep_dma_memcpy(dma_chan, dest_dma, src_dma,
+                                     IOP_ADMA_TEST_SIZE, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -929,6 +895,7 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
        struct page *dest;
        struct page *xor_srcs[IOP_ADMA_NUM_SRC_TEST];
        struct page *zero_sum_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
+       dma_addr_t dma_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
        dma_addr_t dma_addr, dest_dma;
        struct dma_async_tx_descriptor *tx;
        struct dma_chan *dma_chan;
@@ -981,17 +948,13 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
        }
 
        /* test xor */
-       tx = iop_adma_prep_dma_xor(dma_chan, IOP_ADMA_NUM_SRC_TEST,
-                               PAGE_SIZE, 1);
        dest_dma = dma_map_page(dma_chan->device->dev, dest, 0,
                                PAGE_SIZE, DMA_FROM_DEVICE);
-       iop_adma_set_dest(dest_dma, tx, 0);
-
-       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++) {
-               dma_addr = dma_map_page(dma_chan->device->dev, xor_srcs[i], 0,
-                       PAGE_SIZE, DMA_TO_DEVICE);
-               iop_adma_xor_set_src(dma_addr, tx, i);
-       }
+       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++)
+               dma_srcs[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i],
+                                          0, PAGE_SIZE, DMA_TO_DEVICE);
+       tx = iop_adma_prep_dma_xor(dma_chan, dest_dma, dma_srcs,
+                                  IOP_ADMA_NUM_SRC_TEST, PAGE_SIZE, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -1032,13 +995,13 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
 
        zero_sum_result = 1;
 
-       tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
-               PAGE_SIZE, &zero_sum_result, 1);
-       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
-               dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
-                       0, PAGE_SIZE, DMA_TO_DEVICE);
-               iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
-       }
+       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
+               dma_srcs[i] = dma_map_page(dma_chan->device->dev,
+                                          zero_sum_srcs[i], 0, PAGE_SIZE,
+                                          DMA_TO_DEVICE);
+       tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
+                                       IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
+                                       &zero_sum_result, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -1060,10 +1023,9 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
        }
 
        /* test memset */
-       tx = iop_adma_prep_dma_memset(dma_chan, 0, PAGE_SIZE, 1);
        dma_addr = dma_map_page(dma_chan->device->dev, dest, 0,
                        PAGE_SIZE, DMA_FROM_DEVICE);
-       iop_adma_set_dest(dma_addr, tx, 0);
+       tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
@@ -1089,13 +1051,13 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
 
        /* test for non-zero parity sum */
        zero_sum_result = 0;
-       tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
-               PAGE_SIZE, &zero_sum_result, 1);
-       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
-               dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
-                       0, PAGE_SIZE, DMA_TO_DEVICE);
-               iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
-       }
+       for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
+               dma_srcs[i] = dma_map_page(dma_chan->device->dev,
+                                          zero_sum_srcs[i], 0, PAGE_SIZE,
+                                          DMA_TO_DEVICE);
+       tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
+                                       IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
+                                       &zero_sum_result, 1);
 
        cookie = iop_adma_tx_submit(tx);
        iop_adma_issue_pending(dma_chan);
index 18cdcb3..1636806 100644 (file)
@@ -658,4 +658,5 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_AUTHOR("Dell Inc.");
 MODULE_LICENSE("GPL");
-
+/* Any System or BIOS claiming to be by Dell */
+MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*");
index 313c99c..e880d6c 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/dmi.h>
 #include <linux/device.h>
-#include <linux/autoconf.h>
 
 struct dmi_device_attribute{
        struct device_attribute dev_attr;
index 74fac0f..bbd2834 100644 (file)
@@ -27,15 +27,16 @@ config DEBUG_GPIO
 
 comment "I2C GPIO expanders:"
 
-config GPIO_PCA9539
-       tristate "PCA9539 16-bit I/O port"
+config GPIO_PCA953X
+       tristate "PCA953x I/O ports"
        depends on I2C
        help
-         Say yes here to support the PCA9539 16-bit I/O port. These
-         parts are made by NXP and TI.
+         Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit),
+         PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539
+         (16-bit) I/O ports. These parts are made by NXP and TI.
 
          This driver can also be built as a module.  If so, the module
-         will be called pca9539.
+         will be called pca953x.
 
 config GPIO_PCF857X
        tristate "PCF857x, PCA857x, and PCA967x I2C GPIO expanders"
index 470ecd6..fdde992 100644 (file)
@@ -5,5 +5,5 @@ ccflags-$(CONFIG_DEBUG_GPIO)    += -DDEBUG
 obj-$(CONFIG_HAVE_GPIO_LIB)    += gpiolib.o
 
 obj-$(CONFIG_GPIO_MCP23S08)    += mcp23s08.o
-obj-$(CONFIG_GPIO_PCA9539)     += pca9539.o
+obj-$(CONFIG_GPIO_PCA953X)     += pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
diff --git a/drivers/gpio/pca9539.c b/drivers/gpio/pca9539.c
deleted file mode 100644 (file)
index 3e85c92..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- *  pca9539.c - 16-bit I/O port with interrupt and reset
- *
- *  Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
- *  Copyright (C) 2007 Marvell International Ltd.
- *
- *  Derived from drivers/i2c/chips/pca9539.c
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pca9539.h>
-
-#include <asm/gpio.h>
-
-
-#define NR_PCA9539_GPIOS       16
-
-#define PCA9539_INPUT          0
-#define PCA9539_OUTPUT         2
-#define PCA9539_INVERT         4
-#define PCA9539_DIRECTION      6
-
-struct pca9539_chip {
-       unsigned gpio_start;
-       uint16_t reg_output;
-       uint16_t reg_direction;
-
-       struct i2c_client *client;
-       struct gpio_chip gpio_chip;
-};
-
-/* NOTE:  we can't currently rely on fault codes to come from SMBus
- * calls, so we map all errors to EIO here and return zero otherwise.
- */
-static int pca9539_write_reg(struct pca9539_chip *chip, int reg, uint16_t val)
-{
-       if (i2c_smbus_write_word_data(chip->client, reg, val) < 0)
-               return -EIO;
-       else
-               return 0;
-}
-
-static int pca9539_read_reg(struct pca9539_chip *chip, int reg, uint16_t *val)
-{
-       int ret;
-
-       ret = i2c_smbus_read_word_data(chip->client, reg);
-       if (ret < 0) {
-               dev_err(&chip->client->dev, "failed reading register\n");
-               return -EIO;
-       }
-
-       *val = (uint16_t)ret;
-       return 0;
-}
-
-static int pca9539_gpio_direction_input(struct gpio_chip *gc, unsigned off)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       reg_val = chip->reg_direction | (1u << off);
-       ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
-       if (ret)
-               return ret;
-
-       chip->reg_direction = reg_val;
-       return 0;
-}
-
-static int pca9539_gpio_direction_output(struct gpio_chip *gc,
-               unsigned off, int val)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       /* set output level */
-       if (val)
-               reg_val = chip->reg_output | (1u << off);
-       else
-               reg_val = chip->reg_output & ~(1u << off);
-
-       ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
-       if (ret)
-               return ret;
-
-       chip->reg_output = reg_val;
-
-       /* then direction */
-       reg_val = chip->reg_direction & ~(1u << off);
-       ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
-       if (ret)
-               return ret;
-
-       chip->reg_direction = reg_val;
-       return 0;
-}
-
-static int pca9539_gpio_get_value(struct gpio_chip *gc, unsigned off)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       ret = pca9539_read_reg(chip, PCA9539_INPUT, &reg_val);
-       if (ret < 0) {
-               /* NOTE:  diagnostic already emitted; that's all we should
-                * do unless gpio_*_value_cansleep() calls become different
-                * from their nonsleeping siblings (and report faults).
-                */
-               return 0;
-       }
-
-       return (reg_val & (1u << off)) ? 1 : 0;
-}
-
-static void pca9539_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
-{
-       struct pca9539_chip *chip;
-       uint16_t reg_val;
-       int ret;
-
-       chip = container_of(gc, struct pca9539_chip, gpio_chip);
-
-       if (val)
-               reg_val = chip->reg_output | (1u << off);
-       else
-               reg_val = chip->reg_output & ~(1u << off);
-
-       ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
-       if (ret)
-               return;
-
-       chip->reg_output = reg_val;
-}
-
-static int pca9539_init_gpio(struct pca9539_chip *chip)
-{
-       struct gpio_chip *gc;
-
-       gc = &chip->gpio_chip;
-
-       gc->direction_input  = pca9539_gpio_direction_input;
-       gc->direction_output = pca9539_gpio_direction_output;
-       gc->get = pca9539_gpio_get_value;
-       gc->set = pca9539_gpio_set_value;
-
-       gc->base = chip->gpio_start;
-       gc->ngpio = NR_PCA9539_GPIOS;
-       gc->label = "pca9539";
-
-       return gpiochip_add(gc);
-}
-
-static int __devinit pca9539_probe(struct i2c_client *client)
-{
-       struct pca9539_platform_data *pdata;
-       struct pca9539_chip *chip;
-       int ret;
-
-       pdata = client->dev.platform_data;
-       if (pdata == NULL)
-               return -ENODEV;
-
-       chip = kzalloc(sizeof(struct pca9539_chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
-
-       chip->client = client;
-
-       chip->gpio_start = pdata->gpio_base;
-
-       /* initialize cached registers from their original values.
-        * we can't share this chip with another i2c master.
-        */
-       ret = pca9539_read_reg(chip, PCA9539_OUTPUT, &chip->reg_output);
-       if (ret)
-               goto out_failed;
-
-       ret = pca9539_read_reg(chip, PCA9539_DIRECTION, &chip->reg_direction);
-       if (ret)
-               goto out_failed;
-
-       /* set platform specific polarity inversion */
-       ret = pca9539_write_reg(chip, PCA9539_INVERT, pdata->invert);
-       if (ret)
-               goto out_failed;
-
-       ret = pca9539_init_gpio(chip);
-       if (ret)
-               goto out_failed;
-
-       if (pdata->setup) {
-               ret = pdata->setup(client, chip->gpio_chip.base,
-                               chip->gpio_chip.ngpio, pdata->context);
-               if (ret < 0)
-                       dev_warn(&client->dev, "setup failed, %d\n", ret);
-       }
-
-       i2c_set_clientdata(client, chip);
-       return 0;
-
-out_failed:
-       kfree(chip);
-       return ret;
-}
-
-static int pca9539_remove(struct i2c_client *client)
-{
-       struct pca9539_platform_data *pdata = client->dev.platform_data;
-       struct pca9539_chip *chip = i2c_get_clientdata(client);
-       int ret = 0;
-
-       if (pdata->teardown) {
-               ret = pdata->teardown(client, chip->gpio_chip.base,
-                               chip->gpio_chip.ngpio, pdata->context);
-               if (ret < 0) {
-                       dev_err(&client->dev, "%s failed, %d\n",
-                                       "teardown", ret);
-                       return ret;
-               }
-       }
-
-       ret = gpiochip_remove(&chip->gpio_chip);
-       if (ret) {
-               dev_err(&client->dev, "%s failed, %d\n",
-                               "gpiochip_remove()", ret);
-               return ret;
-       }
-
-       kfree(chip);
-       return 0;
-}
-
-static struct i2c_driver pca9539_driver = {
-       .driver = {
-               .name   = "pca9539",
-       },
-       .probe          = pca9539_probe,
-       .remove         = pca9539_remove,
-};
-
-static int __init pca9539_init(void)
-{
-       return i2c_add_driver(&pca9539_driver);
-}
-module_init(pca9539_init);
-
-static void __exit pca9539_exit(void)
-{
-       i2c_del_driver(&pca9539_driver);
-}
-module_exit(pca9539_exit);
-
-MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
-MODULE_DESCRIPTION("GPIO expander driver for PCA9539");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
new file mode 100644 (file)
index 0000000..92583cd
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ *  pca953x.c - 4/8/16 bit I/O ports
+ *
+ *  Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
+ *  Copyright (C) 2007 Marvell International Ltd.
+ *
+ *  Derived from drivers/i2c/chips/pca9539.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/gpio.h>
+
+#define PCA953X_INPUT          0
+#define PCA953X_OUTPUT         1
+#define PCA953X_INVERT         2
+#define PCA953X_DIRECTION      3
+
+/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */
+struct pca953x_desc {
+       char            name[I2C_NAME_SIZE];
+       unsigned long   driver_data;
+};
+
+static const struct pca953x_desc pca953x_descs[] = {
+       { "pca9534", 8, },
+       { "pca9535", 16, },
+       { "pca9536", 4, },
+       { "pca9537", 4, },
+       { "pca9538", 8, },
+       { "pca9539", 16, },
+       /* REVISIT several pca955x parts should work here too */
+};
+
+struct pca953x_chip {
+       unsigned gpio_start;
+       uint16_t reg_output;
+       uint16_t reg_direction;
+
+       struct i2c_client *client;
+       struct gpio_chip gpio_chip;
+};
+
+/* NOTE:  we can't currently rely on fault codes to come from SMBus
+ * calls, so we map all errors to EIO here and return zero otherwise.
+ */
+static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
+{
+       int ret;
+
+       if (chip->gpio_chip.ngpio <= 8)
+               ret = i2c_smbus_write_byte_data(chip->client, reg, val);
+       else
+               ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
+
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "failed writing register\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val)
+{
+       int ret;
+
+       if (chip->gpio_chip.ngpio <= 8)
+               ret = i2c_smbus_read_byte_data(chip->client, reg);
+       else
+               ret = i2c_smbus_read_word_data(chip->client, reg << 1);
+
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "failed reading register\n");
+               return -EIO;
+       }
+
+       *val = (uint16_t)ret;
+       return 0;
+}
+
+static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       reg_val = chip->reg_direction | (1u << off);
+       ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_direction = reg_val;
+       return 0;
+}
+
+static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+               unsigned off, int val)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       /* set output level */
+       if (val)
+               reg_val = chip->reg_output | (1u << off);
+       else
+               reg_val = chip->reg_output & ~(1u << off);
+
+       ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_output = reg_val;
+
+       /* then direction */
+       reg_val = chip->reg_direction & ~(1u << off);
+       ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_direction = reg_val;
+       return 0;
+}
+
+static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
+       if (ret < 0) {
+               /* NOTE:  diagnostic already emitted; that's all we should
+                * do unless gpio_*_value_cansleep() calls become different
+                * from their nonsleeping siblings (and report faults).
+                */
+               return 0;
+       }
+
+       return (reg_val & (1u << off)) ? 1 : 0;
+}
+
+static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+{
+       struct pca953x_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca953x_chip, gpio_chip);
+
+       if (val)
+               reg_val = chip->reg_output | (1u << off);
+       else
+               reg_val = chip->reg_output & ~(1u << off);
+
+       ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
+       if (ret)
+               return;
+
+       chip->reg_output = reg_val;
+}
+
+static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
+{
+       struct gpio_chip *gc;
+
+       gc = &chip->gpio_chip;
+
+       gc->direction_input  = pca953x_gpio_direction_input;
+       gc->direction_output = pca953x_gpio_direction_output;
+       gc->get = pca953x_gpio_get_value;
+       gc->set = pca953x_gpio_set_value;
+
+       gc->base = chip->gpio_start;
+       gc->ngpio = gpios;
+       gc->label = chip->client->name;
+}
+
+static int __devinit pca953x_probe(struct i2c_client *client)
+{
+       struct pca953x_platform_data *pdata;
+       struct pca953x_chip *chip;
+       int ret, i;
+       const struct pca953x_desc *id = NULL;
+
+       pdata = client->dev.platform_data;
+       if (pdata == NULL)
+               return -ENODEV;
+
+       /* this loop vanishes when we get i2c_device_id */
+       for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++)
+               if (!strcmp(pca953x_descs[i].name, client->name)) {
+                       id = pca953x_descs + i;
+                       break;
+               }
+       if (!id)
+               return -ENODEV;
+
+       chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       chip->client = client;
+
+       chip->gpio_start = pdata->gpio_base;
+
+       /* initialize cached registers from their original values.
+        * we can't share this chip with another i2c master.
+        */
+       pca953x_setup_gpio(chip, id->driver_data);
+
+       ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+       if (ret)
+               goto out_failed;
+
+       ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
+       if (ret)
+               goto out_failed;
+
+       /* set platform specific polarity inversion */
+       ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
+       if (ret)
+               goto out_failed;
+
+
+       ret = gpiochip_add(&chip->gpio_chip);
+       if (ret)
+               goto out_failed;
+
+       if (pdata->setup) {
+               ret = pdata->setup(client, chip->gpio_chip.base,
+                               chip->gpio_chip.ngpio, pdata->context);
+               if (ret < 0)
+                       dev_warn(&client->dev, "setup failed, %d\n", ret);
+       }
+
+       i2c_set_clientdata(client, chip);
+       return 0;
+
+out_failed:
+       kfree(chip);
+       return ret;
+}
+
+static int pca953x_remove(struct i2c_client *client)
+{
+       struct pca953x_platform_data *pdata = client->dev.platform_data;
+       struct pca953x_chip *chip = i2c_get_clientdata(client);
+       int ret = 0;
+
+       if (pdata->teardown) {
+               ret = pdata->teardown(client, chip->gpio_chip.base,
+                               chip->gpio_chip.ngpio, pdata->context);
+               if (ret < 0) {
+                       dev_err(&client->dev, "%s failed, %d\n",
+                                       "teardown", ret);
+                       return ret;
+               }
+       }
+
+       ret = gpiochip_remove(&chip->gpio_chip);
+       if (ret) {
+               dev_err(&client->dev, "%s failed, %d\n",
+                               "gpiochip_remove()", ret);
+               return ret;
+       }
+
+       kfree(chip);
+       return 0;
+}
+
+static struct i2c_driver pca953x_driver = {
+       .driver = {
+               .name   = "pca953x",
+       },
+       .probe          = pca953x_probe,
+       .remove         = pca953x_remove,
+};
+
+static int __init pca953x_init(void)
+{
+       return i2c_add_driver(&pca953x_driver);
+}
+module_init(pca953x_init);
+
+static void __exit pca953x_exit(void)
+{
+       i2c_del_driver(&pca953x_driver);
+}
+module_exit(pca953x_exit);
+
+MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("GPIO expander driver for PCA953x");
+MODULE_LICENSE("GPL");
index fd0ef82..6daea89 100644 (file)
@@ -1049,7 +1049,7 @@ static int init_irq (ide_hwif_t *hwif)
         */
        if (!match || match->irq != hwif->irq) {
                int sa = 0;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
                sa = IRQF_SHARED;
 #endif /* __mc68000__ || CONFIG_APUS */
 
@@ -1072,7 +1072,7 @@ static int init_irq (ide_hwif_t *hwif)
                        hwif->rqsize = 65536;
        }
 
-#if !defined(__mc68000__) && !defined(CONFIG_APUS)
+#if !defined(__mc68000__)
        printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
                hwif->io_ports[IDE_DATA_OFFSET],
                hwif->io_ports[IDE_DATA_OFFSET]+7,
@@ -1080,7 +1080,7 @@ static int init_irq (ide_hwif_t *hwif)
 #else
        printk("%s at 0x%08lx on irq %d", hwif->name,
                hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
-#endif /* __mc68000__ && CONFIG_APUS */
+#endif /* __mc68000__ */
        if (match)
                printk(" (%sed with %s)",
                        hwif->sharing_irq ? "shar" : "serializ", match->name);
index 26c82ce..688fcae 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/ide.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
-#include <linux/pata_platform.h>
+#include <linux/ata_platform.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
index 2ae6c60..28ae15e 100644 (file)
@@ -109,7 +109,7 @@ struct h3600_dev {
 static irqreturn_t action_button_handler(int irq, void *dev_id)
 {
        int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
-       struct input_dev *dev = (struct input_dev *) dev_id;
+       struct input_dev *dev = dev_id;
 
        input_report_key(dev, KEY_ENTER, down);
        input_sync(dev);
@@ -120,7 +120,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id)
 static irqreturn_t npower_button_handler(int irq, void *dev_id)
 {
        int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
-       struct input_dev *dev = (struct input_dev *) dev_id;
+       struct input_dev *dev = dev_id;
 
        /*
         * This interrupt is only called when we release the key. So we have
index ee2b0b9..8325022 100644 (file)
@@ -310,7 +310,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        }
                        break;
                case ISDN_CMD_DIAL:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -339,7 +339,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        }
                        return ret;
                case ISDN_CMD_ACCEPTD:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -347,11 +347,11 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                                actcapi_select_b2_protocol_req(card, chan);
                        return 0;
                case ISDN_CMD_ACCEPTB:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        return 0;
                case ISDN_CMD_HANGUP:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -366,7 +366,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        }
                        return 0;
                case ISDN_CMD_SETEAZ:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -386,7 +386,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        actcapi_listen_req(card);
                        return 0;
                case ISDN_CMD_CLREAZ:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
@@ -394,14 +394,14 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                        actcapi_listen_req(card);
                        return 0;
                case ISDN_CMD_SETL2:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if (!(chan = find_channel(card, c->arg & 0x0f)))
                                break;
                        chan->l2prot = (c->arg >> 8);
                        return 0;
                case ISDN_CMD_SETL3:
-                       if (!card->flags & ACT2000_FLAGS_RUNNING)
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
                                return -ENODEV;
                        if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
                                printk(KERN_WARNING "L3 protocol unknown\n");
@@ -524,7 +524,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel)
         act2000_card *card = act2000_findcard(id);
 
         if (card) {
-                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                if (!(card->flags & ACT2000_FLAGS_RUNNING))
                         return -ENODEV;
                 return (len);
         }
@@ -539,7 +539,7 @@ if_readstatus(u_char __user * buf, int len, int id, int channel)
         act2000_card *card = act2000_findcard(id);
        
         if (card) {
-                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                if (!(card->flags & ACT2000_FLAGS_RUNNING))
                         return -ENODEV;
                 return (act2000_readstatus(buf, len, card));
         }
@@ -554,7 +554,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
         act2000_card *card = act2000_findcard(id);
        
         if (card) {
-                if (!card->flags & ACT2000_FLAGS_RUNNING)
+                if (!(card->flags & ACT2000_FLAGS_RUNNING))
                         return -ENODEV;
                return (act2000_sendbuf(card, channel, ack, skb));
         }
index 00a3be5..091deb9 100644 (file)
@@ -350,8 +350,8 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
        unsigned char *src, c;
        int procbytes;
 
-       head = atomic_read(&inbuf->head);
-       tail = atomic_read(&inbuf->tail);
+       head = inbuf->head;
+       tail = inbuf->tail;
        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
 
        if (head != tail) {
@@ -361,7 +361,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
                gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
 
                while (numbytes) {
-                       if (atomic_read(&cs->mstate) == MS_LOCKED) {
+                       if (cs->mstate == MS_LOCKED) {
                                procbytes = lock_loop(src, numbytes, inbuf);
                                src += procbytes;
                                numbytes -= procbytes;
@@ -436,7 +436,7 @@ nextbyte:
                }
 
                gig_dbg(DEBUG_INTR, "setting head to %u", head);
-               atomic_set(&inbuf->head, head);
+               inbuf->head = head;
        }
 }
 EXPORT_SYMBOL_GPL(gigaset_m10x_input);
index af76482..5255b5e 100644 (file)
@@ -73,6 +73,14 @@ static int gigaset_probe(struct usb_interface *interface,
 /* Function will be called if the device is unplugged */
 static void gigaset_disconnect(struct usb_interface *interface);
 
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+
+/* functions called before/after device reset */
+static int gigaset_pre_reset(struct usb_interface *intf);
+static int gigaset_post_reset(struct usb_interface *intf);
+
 static int atread_submit(struct cardstate *, int);
 static void stopurbs(struct bas_bc_state *);
 static int req_submit(struct bc_state *, int, int, int);
@@ -105,8 +113,9 @@ struct bas_cardstate {
        unsigned char           int_in_buf[3];
 
        spinlock_t              lock;           /* locks all following */
-       atomic_t                basstate;       /* bitmap (BS_*) */
+       int                     basstate;       /* bitmap (BS_*) */
        int                     pending;        /* uncompleted base request */
+       wait_queue_head_t       waitqueue;
        int                     rcvbuf_size;    /* size of AT receive buffer */
                                                /* 0: no receive in progress */
        int                     retry_cmd_in;   /* receive req retry count */
@@ -121,10 +130,10 @@ struct bas_cardstate {
 #define BS_ATTIMER     0x020   /* waiting for HD_READY_SEND_ATDATA */
 #define BS_ATRDPEND    0x040   /* urb_cmd_in in use */
 #define BS_ATWRPEND    0x080   /* urb_cmd_out in use */
+#define BS_SUSPEND     0x100   /* USB port suspended */
 
 
 static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver gigaset_usb_driver = {
@@ -132,6 +141,11 @@ static struct usb_driver gigaset_usb_driver = {
        .probe =        gigaset_probe,
        .disconnect =   gigaset_disconnect,
        .id_table =     gigaset_table,
+       .suspend =      gigaset_suspend,
+       .resume =       gigaset_resume,
+       .reset_resume = gigaset_post_reset,
+       .pre_reset =    gigaset_pre_reset,
+       .post_reset =   gigaset_post_reset,
 };
 
 /* get message text for usb_submit_urb return code
@@ -248,12 +262,12 @@ static inline void dump_urb(enum debuglevel level, const char *tag,
        if (urb) {
                gig_dbg(level,
                        "  dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
-                       "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
+                       "hcpriv=0x%08lx, transfer_flags=0x%x,",
                        (unsigned long) urb->dev,
                        usb_pipetype_str(urb->pipe),
                        usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
                        usb_pipein(urb->pipe) ? "in" : "out",
-                       urb->status, (unsigned long) urb->hcpriv,
+                       (unsigned long) urb->hcpriv,
                        urb->transfer_flags);
                gig_dbg(level,
                        "  transfer_buffer=0x%08lx[%d], actual_length=%d, "
@@ -355,27 +369,27 @@ static void check_pending(struct bas_cardstate *ucs)
        case 0:
                break;
        case HD_OPEN_ATCHANNEL:
-               if (atomic_read(&ucs->basstate) & BS_ATOPEN)
+               if (ucs->basstate & BS_ATOPEN)
                        ucs->pending = 0;
                break;
        case HD_OPEN_B1CHANNEL:
-               if (atomic_read(&ucs->basstate) & BS_B1OPEN)
+               if (ucs->basstate & BS_B1OPEN)
                        ucs->pending = 0;
                break;
        case HD_OPEN_B2CHANNEL:
-               if (atomic_read(&ucs->basstate) & BS_B2OPEN)
+               if (ucs->basstate & BS_B2OPEN)
                        ucs->pending = 0;
                break;
        case HD_CLOSE_ATCHANNEL:
-               if (!(atomic_read(&ucs->basstate) & BS_ATOPEN))
+               if (!(ucs->basstate & BS_ATOPEN))
                        ucs->pending = 0;
                break;
        case HD_CLOSE_B1CHANNEL:
-               if (!(atomic_read(&ucs->basstate) & BS_B1OPEN))
+               if (!(ucs->basstate & BS_B1OPEN))
                        ucs->pending = 0;
                break;
        case HD_CLOSE_B2CHANNEL:
-               if (!(atomic_read(&ucs->basstate) & BS_B2OPEN))
+               if (!(ucs->basstate & BS_B2OPEN))
                        ucs->pending = 0;
                break;
        case HD_DEVICE_INIT_ACK:                /* no reply expected */
@@ -441,8 +455,8 @@ inline static int update_basstate(struct bas_cardstate *ucs,
        int state;
 
        spin_lock_irqsave(&ucs->lock, flags);
-       state = atomic_read(&ucs->basstate);
-       atomic_set(&ucs->basstate, (state & ~clear) | set);
+       state = ucs->basstate;
+       ucs->basstate = (state & ~clear) | set;
        spin_unlock_irqrestore(&ucs->lock, flags);
        return state;
 }
@@ -459,11 +473,13 @@ static void read_ctrl_callback(struct urb *urb)
        struct inbuf_t *inbuf = urb->context;
        struct cardstate *cs = inbuf->cs;
        struct bas_cardstate *ucs = cs->hw.bas;
+       int status = urb->status;
        int have_data = 0;
        unsigned numbytes;
        int rc;
 
        update_basstate(ucs, 0, BS_ATRDPEND);
+       wake_up(&ucs->waitqueue);
 
        if (!ucs->rcvbuf_size) {
                dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
@@ -472,7 +488,7 @@ static void read_ctrl_callback(struct urb *urb)
 
        del_timer(&ucs->timer_cmd_in);
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                         /* normal completion */
                numbytes = urb->actual_length;
                if (unlikely(numbytes != ucs->rcvbuf_size)) {
@@ -506,12 +522,12 @@ static void read_ctrl_callback(struct urb *urb)
        case -ESHUTDOWN:                /* device shut down */
                /* no action necessary */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                break;
 
        default:                        /* severe trouble */
                dev_warn(cs->dev, "control read: %s\n",
-                        get_usb_statmsg(urb->status));
+                        get_usb_statmsg(status));
                if (ucs->retry_cmd_in++ < BAS_RETRY) {
                        dev_notice(cs->dev, "control read: retry %d\n",
                                   ucs->retry_cmd_in);
@@ -550,17 +566,28 @@ static void read_ctrl_callback(struct urb *urb)
 static int atread_submit(struct cardstate *cs, int timeout)
 {
        struct bas_cardstate *ucs = cs->hw.bas;
+       int basstate;
        int ret;
 
        gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)",
                ucs->rcvbuf_size);
 
-       if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) {
+       basstate = update_basstate(ucs, BS_ATRDPEND, 0);
+       if (basstate & BS_ATRDPEND) {
                dev_err(cs->dev,
                        "could not submit HD_READ_ATMESSAGE: URB busy\n");
                return -EBUSY;
        }
 
+       if (basstate & BS_SUSPEND) {
+               dev_notice(cs->dev,
+                          "HD_READ_ATMESSAGE not submitted, "
+                          "suspend in progress\n");
+               update_basstate(ucs, 0, BS_ATRDPEND);
+               /* treat like disconnect */
+               return -ENODEV;
+       }
+
        ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ;
        ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE;
        ucs->dr_cmd_in.wValue = 0;
@@ -601,12 +628,13 @@ static void read_int_callback(struct urb *urb)
        struct cardstate *cs = urb->context;
        struct bas_cardstate *ucs = cs->hw.bas;
        struct bc_state *bcs;
+       int status = urb->status;
        unsigned long flags;
        int rc;
        unsigned l;
        int channel;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ENOENT:                   /* cancelled */
@@ -614,7 +642,7 @@ static void read_int_callback(struct urb *urb)
        case -EINPROGRESS:              /* pending */
                /* ignore silently */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        case -ENODEV:                   /* device removed */
        case -ESHUTDOWN:                /* device shut down */
@@ -623,7 +651,7 @@ static void read_int_callback(struct urb *urb)
                return;
        default:                /* severe trouble */
                dev_warn(cs->dev, "interrupt read: %s\n",
-                        get_usb_statmsg(urb->status));
+                        get_usb_statmsg(status));
                //FIXME corrective action? resubmission always ok?
                goto resubmit;
        }
@@ -745,6 +773,7 @@ static void read_int_callback(struct urb *urb)
        }
 
        check_pending(ucs);
+       wake_up(&ucs->waitqueue);
 
 resubmit:
        rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -766,17 +795,18 @@ static void read_iso_callback(struct urb *urb)
 {
        struct bc_state *bcs;
        struct bas_bc_state *ubc;
+       int status = urb->status;
        unsigned long flags;
        int i, rc;
 
        /* status codes not worth bothering the tasklet with */
-       if (unlikely(urb->status == -ENOENT ||
-                    urb->status == -ECONNRESET ||
-                    urb->status == -EINPROGRESS ||
-                    urb->status == -ENODEV ||
-                    urb->status == -ESHUTDOWN)) {
+       if (unlikely(status == -ENOENT ||
+                    status == -ECONNRESET ||
+                    status == -EINPROGRESS ||
+                    status == -ENODEV ||
+                    status == -ESHUTDOWN)) {
                gig_dbg(DEBUG_ISO, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        }
 
@@ -787,10 +817,11 @@ static void read_iso_callback(struct urb *urb)
        if (likely(ubc->isoindone == NULL)) {
                /* pass URB to tasklet */
                ubc->isoindone = urb;
+               ubc->isoinstatus = status;
                tasklet_schedule(&ubc->rcvd_tasklet);
        } else {
                /* tasklet still busy, drop data and resubmit URB */
-               ubc->loststatus = urb->status;
+               ubc->loststatus = status;
                for (i = 0; i < BAS_NUMFRAMES; i++) {
                        ubc->isoinlost += urb->iso_frame_desc[i].actual_length;
                        if (unlikely(urb->iso_frame_desc[i].status != 0 &&
@@ -800,7 +831,7 @@ static void read_iso_callback(struct urb *urb)
                        urb->iso_frame_desc[i].status = 0;
                        urb->iso_frame_desc[i].actual_length = 0;
                }
-               if (likely(atomic_read(&ubc->running))) {
+               if (likely(ubc->running)) {
                        /* urb->dev is clobbered by USB subsystem */
                        urb->dev = bcs->cs->hw.bas->udev;
                        urb->transfer_flags = URB_ISO_ASAP;
@@ -831,22 +862,24 @@ static void write_iso_callback(struct urb *urb)
 {
        struct isow_urbctx_t *ucx;
        struct bas_bc_state *ubc;
+       int status = urb->status;
        unsigned long flags;
 
        /* status codes not worth bothering the tasklet with */
-       if (unlikely(urb->status == -ENOENT ||
-                    urb->status == -ECONNRESET ||
-                    urb->status == -EINPROGRESS ||
-                    urb->status == -ENODEV ||
-                    urb->status == -ESHUTDOWN)) {
+       if (unlikely(status == -ENOENT ||
+                    status == -ECONNRESET ||
+                    status == -EINPROGRESS ||
+                    status == -ENODEV ||
+                    status == -ESHUTDOWN)) {
                gig_dbg(DEBUG_ISO, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        }
 
        /* pass URB context to tasklet */
        ucx = urb->context;
        ubc = ucx->bcs->hw.bas;
+       ucx->status = status;
 
        spin_lock_irqsave(&ubc->isooutlock, flags);
        ubc->isooutovfl = ubc->isooutdone;
@@ -875,7 +908,7 @@ static int starturbs(struct bc_state *bcs)
                bcs->inputstate |= INS_flag_hunt;
 
        /* submit all isochronous input URBs */
-       atomic_set(&ubc->running, 1);
+       ubc->running = 1;
        for (k = 0; k < BAS_INURBS; k++) {
                urb = ubc->isoinurbs[k];
                if (!urb) {
@@ -932,15 +965,15 @@ static int starturbs(struct bc_state *bcs)
                ubc->isoouturbs[k].limit = -1;
        }
 
-       /* submit two URBs, keep third one */
-       for (k = 0; k < 2; ++k) {
+       /* keep one URB free, submit the others */
+       for (k = 0; k < BAS_OUTURBS-1; ++k) {
                dump_urb(DEBUG_ISO, "Initial isoc write", urb);
                rc = usb_submit_urb(ubc->isoouturbs[k].urb, GFP_ATOMIC);
                if (rc != 0)
                        goto error;
        }
        dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb);
-       ubc->isooutfree = &ubc->isoouturbs[2];
+       ubc->isooutfree = &ubc->isoouturbs[BAS_OUTURBS-1];
        ubc->isooutdone = ubc->isooutovfl = NULL;
        return 0;
  error:
@@ -958,7 +991,7 @@ static void stopurbs(struct bas_bc_state *ubc)
 {
        int k, rc;
 
-       atomic_set(&ubc->running, 0);
+       ubc->running = 0;
 
        for (k = 0; k < BAS_INURBS; ++k) {
                rc = usb_unlink_urb(ubc->isoinurbs[k]);
@@ -1034,7 +1067,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
                        }
                        break;
                }
-               ucx->limit = atomic_read(&ubc->isooutbuf->nextread);
+               ucx->limit = ubc->isooutbuf->nextread;
                ifd->status = 0;
                ifd->actual_length = 0;
        }
@@ -1070,6 +1103,7 @@ static void write_iso_tasklet(unsigned long data)
        struct cardstate *cs = bcs->cs;
        struct isow_urbctx_t *done, *next, *ovfl;
        struct urb *urb;
+       int status;
        struct usb_iso_packet_descriptor *ifd;
        int offset;
        unsigned long flags;
@@ -1080,7 +1114,7 @@ static void write_iso_tasklet(unsigned long data)
 
        /* loop while completed URBs arrive in time */
        for (;;) {
-               if (unlikely(!(atomic_read(&ubc->running)))) {
+               if (unlikely(!(ubc->running))) {
                        gig_dbg(DEBUG_ISO, "%s: not running", __func__);
                        return;
                }
@@ -1126,7 +1160,8 @@ static void write_iso_tasklet(unsigned long data)
 
                /* process completed URB */
                urb = done->urb;
-               switch (urb->status) {
+               status = done->status;
+               switch (status) {
                case -EXDEV:                    /* partial completion */
                        gig_dbg(DEBUG_ISO, "%s: URB partially completed",
                                __func__);
@@ -1179,12 +1214,12 @@ static void write_iso_tasklet(unsigned long data)
                        break;
                default:                        /* severe trouble */
                        dev_warn(cs->dev, "isochronous write: %s\n",
-                                get_usb_statmsg(urb->status));
+                                get_usb_statmsg(status));
                }
 
                /* mark the write buffer area covered by this URB as free */
                if (done->limit >= 0)
-                       atomic_set(&ubc->isooutbuf->read, done->limit);
+                       ubc->isooutbuf->read = done->limit;
 
                /* mark URB as free */
                spin_lock_irqsave(&ubc->isooutlock, flags);
@@ -1233,6 +1268,7 @@ static void read_iso_tasklet(unsigned long data)
        struct bas_bc_state *ubc = bcs->hw.bas;
        struct cardstate *cs = bcs->cs;
        struct urb *urb;
+       int status;
        char *rcvbuf;
        unsigned long flags;
        int totleft, numbytes, offset, frame, rc;
@@ -1245,6 +1281,7 @@ static void read_iso_tasklet(unsigned long data)
                        spin_unlock_irqrestore(&ubc->isoinlock, flags);
                        return;
                }
+               status = ubc->isoinstatus;
                ubc->isoindone = NULL;
                if (unlikely(ubc->loststatus != -EINPROGRESS)) {
                        dev_warn(cs->dev,
@@ -1256,15 +1293,15 @@ static void read_iso_tasklet(unsigned long data)
                }
                spin_unlock_irqrestore(&ubc->isoinlock, flags);
 
-               if (unlikely(!(atomic_read(&ubc->running)))) {
+               if (unlikely(!(ubc->running))) {
                        gig_dbg(DEBUG_ISO,
                                "%s: channel not running, "
                                "dropped URB with status: %s",
-                               __func__, get_usb_statmsg(urb->status));
+                               __func__, get_usb_statmsg(status));
                        return;
                }
 
-               switch (urb->status) {
+               switch (status) {
                case 0:                         /* normal completion */
                        break;
                case -EXDEV:                    /* inspect individual frames
@@ -1276,7 +1313,7 @@ static void read_iso_tasklet(unsigned long data)
                case -ECONNRESET:
                case -EINPROGRESS:
                        gig_dbg(DEBUG_ISO, "%s: %s",
-                               __func__, get_usb_statmsg(urb->status));
+                               __func__, get_usb_statmsg(status));
                        continue;               /* -> skip */
                case -EPIPE:
                        dev_err(cs->dev, "isochronous read stalled\n");
@@ -1284,7 +1321,7 @@ static void read_iso_tasklet(unsigned long data)
                        continue;               /* -> skip */
                default:                        /* severe trouble */
                        dev_warn(cs->dev, "isochronous read: %s\n",
-                                get_usb_statmsg(urb->status));
+                                get_usb_statmsg(status));
                        goto error;
                }
 
@@ -1406,6 +1443,8 @@ static void req_timeout(unsigned long data)
                dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
                         pending);
        }
+
+       wake_up(&ucs->waitqueue);
 }
 
 /* write_ctrl_callback
@@ -1418,11 +1457,12 @@ static void req_timeout(unsigned long data)
 static void write_ctrl_callback(struct urb *urb)
 {
        struct bas_cardstate *ucs = urb->context;
+       int status = urb->status;
        int rc;
        unsigned long flags;
 
        /* check status */
-       switch (urb->status) {
+       switch (status) {
        case 0:                                 /* normal completion */
                spin_lock_irqsave(&ucs->lock, flags);
                switch (ucs->pending) {
@@ -1441,20 +1481,22 @@ static void write_ctrl_callback(struct urb *urb)
        case -ESHUTDOWN:                /* device shut down */
                /* ignore silently */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                break;
 
        default:                                /* any failure */
-               if (++ucs->retry_ctrl > BAS_RETRY) {
+               /* don't retry if suspend requested */
+               if (++ucs->retry_ctrl > BAS_RETRY ||
+                   (ucs->basstate & BS_SUSPEND)) {
                        dev_err(&ucs->interface->dev,
                                "control request 0x%02x failed: %s\n",
                                ucs->dr_ctrl.bRequest,
-                               get_usb_statmsg(urb->status));
+                               get_usb_statmsg(status));
                        break;          /* give up */
                }
                dev_notice(&ucs->interface->dev,
                           "control request 0x%02x: %s, retry %d\n",
-                          ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status),
+                          ucs->dr_ctrl.bRequest, get_usb_statmsg(status),
                           ucs->retry_ctrl);
                /* urb->dev is clobbered by USB subsystem */
                urb->dev = ucs->udev;
@@ -1474,6 +1516,7 @@ static void write_ctrl_callback(struct urb *urb)
        del_timer(&ucs->timer_ctrl);
        ucs->pending = 0;
        spin_unlock_irqrestore(&ucs->lock, flags);
+       wake_up(&ucs->waitqueue);
 }
 
 /* req_submit
@@ -1548,37 +1591,46 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
  */
 static int gigaset_init_bchannel(struct bc_state *bcs)
 {
+       struct cardstate *cs = bcs->cs;
        int req, ret;
        unsigned long flags;
 
-       spin_lock_irqsave(&bcs->cs->lock, flags);
-       if (unlikely(!bcs->cs->connected)) {
+       spin_lock_irqsave(&cs->lock, flags);
+       if (unlikely(!cs->connected)) {
                gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+               spin_unlock_irqrestore(&cs->lock, flags);
                return -ENODEV;
        }
 
+       if (cs->hw.bas->basstate & BS_SUSPEND) {
+               dev_notice(cs->dev,
+                          "not starting isochronous I/O, "
+                          "suspend in progress\n");
+               spin_unlock_irqrestore(&cs->lock, flags);
+               return -EHOSTUNREACH;
+       }
+
        if ((ret = starturbs(bcs)) < 0) {
-               dev_err(bcs->cs->dev,
+               dev_err(cs->dev,
                        "could not start isochronous I/O for channel B%d: %s\n",
                        bcs->channel + 1,
                        ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret));
                if (ret != -ENODEV)
                        error_hangup(bcs);
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+               spin_unlock_irqrestore(&cs->lock, flags);
                return ret;
        }
 
        req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
        if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
-               dev_err(bcs->cs->dev, "could not open channel B%d\n",
+               dev_err(cs->dev, "could not open channel B%d\n",
                        bcs->channel + 1);
                stopurbs(bcs->hw.bas);
                if (ret != -ENODEV)
                        error_hangup(bcs);
        }
 
-       spin_unlock_irqrestore(&bcs->cs->lock, flags);
+       spin_unlock_irqrestore(&cs->lock, flags);
        return ret;
 }
 
@@ -1594,20 +1646,20 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
  */
 static int gigaset_close_bchannel(struct bc_state *bcs)
 {
+       struct cardstate *cs = bcs->cs;
        int req, ret;
        unsigned long flags;
 
-       spin_lock_irqsave(&bcs->cs->lock, flags);
-       if (unlikely(!bcs->cs->connected)) {
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+       spin_lock_irqsave(&cs->lock, flags);
+       if (unlikely(!cs->connected)) {
+               spin_unlock_irqrestore(&cs->lock, flags);
                gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__);
                return -ENODEV;
        }
 
-       if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
-             (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
+       if (!(cs->hw.bas->basstate & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
                /* channel not running: just signal common.c */
-               spin_unlock_irqrestore(&bcs->cs->lock, flags);
+               spin_unlock_irqrestore(&cs->lock, flags);
                gigaset_bchannel_down(bcs);
                return 0;
        }
@@ -1615,10 +1667,10 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
        /* channel running: tell device to close it */
        req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
        if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
-               dev_err(bcs->cs->dev, "closing channel B%d failed\n",
+               dev_err(cs->dev, "closing channel B%d failed\n",
                        bcs->channel + 1);
 
-       spin_unlock_irqrestore(&bcs->cs->lock, flags);
+       spin_unlock_irqrestore(&cs->lock, flags);
        return ret;
 }
 
@@ -1665,12 +1717,14 @@ static void write_command_callback(struct urb *urb)
 {
        struct cardstate *cs = urb->context;
        struct bas_cardstate *ucs = cs->hw.bas;
+       int status = urb->status;
        unsigned long flags;
 
        update_basstate(ucs, 0, BS_ATWRPEND);
+       wake_up(&ucs->waitqueue);
 
        /* check status */
-       switch (urb->status) {
+       switch (status) {
        case 0:                                 /* normal completion */
                break;
        case -ENOENT:                   /* cancelled */
@@ -1680,26 +1734,33 @@ static void write_command_callback(struct urb *urb)
        case -ESHUTDOWN:                /* device shut down */
                /* ignore silently */
                gig_dbg(DEBUG_USBREQ, "%s: %s",
-                       __func__, get_usb_statmsg(urb->status));
+                       __func__, get_usb_statmsg(status));
                return;
        default:                                /* any failure */
                if (++ucs->retry_cmd_out > BAS_RETRY) {
                        dev_warn(cs->dev,
                                 "command write: %s, "
                                 "giving up after %d retries\n",
-                                get_usb_statmsg(urb->status),
+                                get_usb_statmsg(status),
                                 ucs->retry_cmd_out);
                        break;
                }
+               if (ucs->basstate & BS_SUSPEND) {
+                       dev_warn(cs->dev,
+                                "command write: %s, "
+                                "won't retry - suspend requested\n",
+                                get_usb_statmsg(status));
+                       break;
+               }
                if (cs->cmdbuf == NULL) {
                        dev_warn(cs->dev,
                                 "command write: %s, "
                                 "cannot retry - cmdbuf gone\n",
-                                get_usb_statmsg(urb->status));
+                                get_usb_statmsg(status));
                        break;
                }
                dev_notice(cs->dev, "command write: %s, retry %d\n",
-                          get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+                          get_usb_statmsg(status), ucs->retry_cmd_out);
                if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0)
                        /* resubmitted - bypass regular exit block */
                        return;
@@ -1799,8 +1860,14 @@ static int start_cbsend(struct cardstate *cs)
        int rc;
        int retval = 0;
 
+       /* check if suspend requested */
+       if (ucs->basstate & BS_SUSPEND) {
+               gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "suspending");
+               return -EHOSTUNREACH;
+       }
+
        /* check if AT channel is open */
-       if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
+       if (!(ucs->basstate & BS_ATOPEN)) {
                gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
                rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
                if (rc < 0) {
@@ -1816,8 +1883,7 @@ static int start_cbsend(struct cardstate *cs)
        /* try to send first command in queue */
        spin_lock_irqsave(&cs->cmdlock, flags);
 
-       while ((cb = cs->cmdbuf) != NULL &&
-              atomic_read(&ucs->basstate) & BS_ATREADY) {
+       while ((cb = cs->cmdbuf) != NULL && (ucs->basstate & BS_ATREADY)) {
                ucs->retry_cmd_out = 0;
                rc = atwrite_submit(cs, cb->buf, cb->len);
                if (unlikely(rc)) {
@@ -1855,7 +1921,7 @@ static int gigaset_write_cmd(struct cardstate *cs,
        unsigned long flags;
        int rc;
 
-       gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+       gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
@@ -1970,7 +2036,7 @@ static int gigaset_freebcshw(struct bc_state *bcs)
                return 0;
 
        /* kill URBs and tasklets before freeing - better safe than sorry */
-       atomic_set(&ubc->running, 0);
+       ubc->running = 0;
        gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__);
        for (i = 0; i < BAS_OUTURBS; ++i) {
                usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2005,7 +2071,7 @@ static int gigaset_initbcshw(struct bc_state *bcs)
                return 0;
        }
 
-       atomic_set(&ubc->running, 0);
+       ubc->running = 0;
        atomic_set(&ubc->corrbytes, 0);
        spin_lock_init(&ubc->isooutlock);
        for (i = 0; i < BAS_OUTURBS; ++i) {
@@ -2050,7 +2116,7 @@ static void gigaset_reinitbcshw(struct bc_state *bcs)
 {
        struct bas_bc_state *ubc = bcs->hw.bas;
 
-       atomic_set(&bcs->hw.bas->running, 0);
+       bcs->hw.bas->running = 0;
        atomic_set(&bcs->hw.bas->corrbytes, 0);
        bcs->hw.bas->numsub = 0;
        spin_lock_init(&ubc->isooutlock);
@@ -2081,10 +2147,11 @@ static int gigaset_initcshw(struct cardstate *cs)
        spin_lock_init(&ucs->lock);
        ucs->pending = 0;
 
-       atomic_set(&ucs->basstate, 0);
+       ucs->basstate = 0;
        init_timer(&ucs->timer_ctrl);
        init_timer(&ucs->timer_atrdy);
        init_timer(&ucs->timer_cmd_in);
+       init_waitqueue_head(&ucs->waitqueue);
 
        return 1;
 }
@@ -2102,7 +2169,7 @@ static void freeurbs(struct cardstate *cs)
        int i, j;
 
        gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__);
-       for (j = 0; j < 2; ++j) {
+       for (j = 0; j < BAS_CHANNELS; ++j) {
                ubc = cs->bcs[j].hw.bas;
                for (i = 0; i < BAS_OUTURBS; ++i) {
                        usb_kill_urb(ubc->isoouturbs[i].urb);
@@ -2179,11 +2246,11 @@ static int gigaset_probe(struct usb_interface *interface,
                 __func__, le16_to_cpu(udev->descriptor.idVendor),
                 le16_to_cpu(udev->descriptor.idProduct));
 
-       cs = gigaset_getunassignedcs(driver);
-       if (!cs) {
-               dev_err(&udev->dev, "no free cardstate\n");
+       /* allocate memory for our device state and intialize it */
+       cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode,
+                           GIGASET_MODULENAME);
+       if (!cs)
                return -ENODEV;
-       }
        ucs = cs->hw.bas;
 
        /* save off device structure ptrs for later use */
@@ -2203,7 +2270,7 @@ static int gigaset_probe(struct usb_interface *interface,
            !(ucs->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL)))
                goto allocerr;
 
-       for (j = 0; j < 2; ++j) {
+       for (j = 0; j < BAS_CHANNELS; ++j) {
                ubc = cs->bcs[j].hw.bas;
                for (i = 0; i < BAS_OUTURBS; ++i)
                        if (!(ubc->isoouturbs[i].urb =
@@ -2237,7 +2304,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        /* tell common part that the device is ready */
        if (startmode == SM_LOCKED)
-               atomic_set(&cs->mstate, MS_LOCKED);
+               cs->mstate = MS_LOCKED;
 
        /* save address of controller structure */
        usb_set_intfdata(interface, cs);
@@ -2252,7 +2319,7 @@ allocerr:
 error:
        freeurbs(cs);
        usb_set_intfdata(interface, NULL);
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
        return -ENODEV;
 }
 
@@ -2272,11 +2339,10 @@ static void gigaset_disconnect(struct usb_interface *interface)
        dev_info(cs->dev, "disconnecting Gigaset base\n");
 
        /* mark base as not ready, all channels disconnected */
-       atomic_set(&ucs->basstate, 0);
+       ucs->basstate = 0;
 
        /* tell LL all channels are down */
-       //FIXME shouldn't gigaset_stop() do this?
-       for (j = 0; j < 2; ++j)
+       for (j = 0; j < BAS_CHANNELS; ++j)
                gigaset_bchannel_down(cs->bcs + j);
 
        /* stop driver (common part) */
@@ -2295,9 +2361,113 @@ static void gigaset_disconnect(struct usb_interface *interface)
        ucs->interface = NULL;
        ucs->udev = NULL;
        cs->dev = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
 }
 
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+       struct bas_cardstate *ucs = cs->hw.bas;
+       int rc;
+
+       /* set suspend flag; this stops AT command/response traffic */
+       if (update_basstate(ucs, BS_SUSPEND, 0) & BS_SUSPEND) {
+               gig_dbg(DEBUG_SUSPEND, "already suspended");
+               return 0;
+       }
+
+       /* wait a bit for blocking conditions to go away */
+       rc = wait_event_timeout(ucs->waitqueue,
+                       !(ucs->basstate &
+                         (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)),
+                       BAS_TIMEOUT*HZ/10);
+       gig_dbg(DEBUG_SUSPEND, "wait_event_timeout() -> %d", rc);
+
+       /* check for conditions preventing suspend */
+       if (ucs->basstate & (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)) {
+               dev_warn(cs->dev, "cannot suspend:\n");
+               if (ucs->basstate & BS_B1OPEN)
+                       dev_warn(cs->dev, " B channel 1 open\n");
+               if (ucs->basstate & BS_B2OPEN)
+                       dev_warn(cs->dev, " B channel 2 open\n");
+               if (ucs->basstate & BS_ATRDPEND)
+                       dev_warn(cs->dev, " receiving AT reply\n");
+               if (ucs->basstate & BS_ATWRPEND)
+                       dev_warn(cs->dev, " sending AT command\n");
+               update_basstate(ucs, 0, BS_SUSPEND);
+               return -EBUSY;
+       }
+
+       /* close AT channel if open */
+       if (ucs->basstate & BS_ATOPEN) {
+               gig_dbg(DEBUG_SUSPEND, "closing AT channel");
+               rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, 0);
+               if (rc) {
+                       update_basstate(ucs, 0, BS_SUSPEND);
+                       return rc;
+               }
+               wait_event_timeout(ucs->waitqueue, !ucs->pending,
+                                  BAS_TIMEOUT*HZ/10);
+               /* in case of timeout, proceed anyway */
+       }
+
+       /* kill all URBs and timers that might still be pending */
+       usb_kill_urb(ucs->urb_ctrl);
+       usb_kill_urb(ucs->urb_int_in);
+       del_timer_sync(&ucs->timer_ctrl);
+
+       gig_dbg(DEBUG_SUSPEND, "suspend complete");
+       return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+       struct bas_cardstate *ucs = cs->hw.bas;
+       int rc;
+
+       /* resubmit interrupt URB for spontaneous messages from base */
+       rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
+       if (rc) {
+               dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
+                       get_usb_rcmsg(rc));
+               return rc;
+       }
+
+       /* clear suspend flag to reallow activity */
+       update_basstate(ucs, 0, BS_SUSPEND);
+
+       gig_dbg(DEBUG_SUSPEND, "resume complete");
+       return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+       /* handle just like suspend */
+       return gigaset_suspend(intf, PMSG_ON);
+}
+
+/* gigaset_post_reset
+ * This function is called after the USB connection has been reset.
+ */
+static int gigaset_post_reset(struct usb_interface *intf)
+{
+       /* FIXME: send HD_DEVICE_INIT_ACK? */
+
+       /* resume operations */
+       return gigaset_resume(intf);
+}
+
+
 static const struct gigaset_ops gigops = {
        gigaset_write_cmd,
        gigaset_write_room,
@@ -2330,12 +2500,6 @@ static int __init bas_gigaset_init(void)
                                       &gigops, THIS_MODULE)) == NULL)
                goto error;
 
-       /* allocate memory for our device state and intialize it */
-       cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode,
-                                  GIGASET_MODULENAME);
-       if (!cardstate)
-               goto error;
-
        /* register this driver with the USB subsystem */
        result = usb_register(&gigaset_usb_driver);
        if (result < 0) {
@@ -2347,9 +2511,7 @@ static int __init bas_gigaset_init(void)
        info(DRIVER_DESC);
        return 0;
 
-error: if (cardstate)
-               gigaset_freecs(cardstate);
-       cardstate = NULL;
+error:
        if (driver)
                gigaset_freedriver(driver);
        driver = NULL;
@@ -2361,43 +2523,50 @@ error:  if (cardstate)
  */
 static void __exit bas_gigaset_exit(void)
 {
-       struct bas_cardstate *ucs = cardstate->hw.bas;
+       struct bas_cardstate *ucs;
+       int i;
 
        gigaset_blockdriver(driver); /* => probe will fail
                                      * => no gigaset_start any more
                                      */
 
-       gigaset_shutdown(cardstate);
-       /* from now on, no isdn callback should be possible */
-
-       /* close all still open channels */
-       if (atomic_read(&ucs->basstate) & BS_B1OPEN) {
-               gig_dbg(DEBUG_INIT, "closing B1 channel");
-               usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
-                               HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0,
-                               NULL, 0, BAS_TIMEOUT);
-       }
-       if (atomic_read(&ucs->basstate) & BS_B2OPEN) {
-               gig_dbg(DEBUG_INIT, "closing B2 channel");
-               usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
-                               HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0,
-                               NULL, 0, BAS_TIMEOUT);
-       }
-       if (atomic_read(&ucs->basstate) & BS_ATOPEN) {
-               gig_dbg(DEBUG_INIT, "closing AT channel");
-               usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0),
-                               HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0,
-                               NULL, 0, BAS_TIMEOUT);
+       /* stop all connected devices */
+       for (i = 0; i < driver->minors; i++) {
+               if (gigaset_shutdown(driver->cs + i) < 0)
+                       continue;               /* no device */
+               /* from now on, no isdn callback should be possible */
+
+               /* close all still open channels */
+               ucs = driver->cs[i].hw.bas;
+               if (ucs->basstate & BS_B1OPEN) {
+                       gig_dbg(DEBUG_INIT, "closing B1 channel");
+                       usb_control_msg(ucs->udev,
+                                       usb_sndctrlpipe(ucs->udev, 0),
+                                       HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ,
+                                       0, 0, NULL, 0, BAS_TIMEOUT);
+               }
+               if (ucs->basstate & BS_B2OPEN) {
+                       gig_dbg(DEBUG_INIT, "closing B2 channel");
+                       usb_control_msg(ucs->udev,
+                                       usb_sndctrlpipe(ucs->udev, 0),
+                                       HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ,
+                                       0, 0, NULL, 0, BAS_TIMEOUT);
+               }
+               if (ucs->basstate & BS_ATOPEN) {
+                       gig_dbg(DEBUG_INIT, "closing AT channel");
+                       usb_control_msg(ucs->udev,
+                                       usb_sndctrlpipe(ucs->udev, 0),
+                                       HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ,
+                                       0, 0, NULL, 0, BAS_TIMEOUT);
+               }
+               ucs->basstate = 0;
        }
-       atomic_set(&ucs->basstate, 0);
 
        /* deregister this driver with the USB subsystem */
        usb_deregister(&gigaset_usb_driver);
        /* this will call the disconnect-callback */
        /* from now on, no disconnect/probe callback should be running */
 
-       gigaset_freecs(cardstate);
-       cardstate = NULL;
        gigaset_freedriver(driver);
        driver = NULL;
 }
index acd4171..aacedec 100644 (file)
@@ -31,7 +31,6 @@ MODULE_PARM_DESC(debug, "debug level");
 /* driver state flags */
 #define VALID_MINOR    0x01
 #define VALID_ID       0x02
-#define ASSIGNED       0x04
 
 void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
                        size_t len, const unsigned char *buf)
@@ -178,7 +177,7 @@ int gigaset_get_channel(struct bc_state *bcs)
        unsigned long flags;
 
        spin_lock_irqsave(&bcs->cs->lock, flags);
-       if (bcs->use_count) {
+       if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) {
                gig_dbg(DEBUG_ANY, "could not allocate channel %d",
                        bcs->channel);
                spin_unlock_irqrestore(&bcs->cs->lock, flags);
@@ -203,6 +202,7 @@ void gigaset_free_channel(struct bc_state *bcs)
        }
        --bcs->use_count;
        bcs->busy = 0;
+       module_put(bcs->cs->driver->owner);
        gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
        spin_unlock_irqrestore(&bcs->cs->lock, flags);
 }
@@ -356,31 +356,28 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv)
 {
        unsigned long flags;
        unsigned i;
+       struct cardstate *cs;
        struct cardstate *ret = NULL;
 
        spin_lock_irqsave(&drv->lock, flags);
+       if (drv->blocked)
+               goto exit;
        for (i = 0; i < drv->minors; ++i) {
-               if (!(drv->flags[i] & VALID_MINOR)) {
-                       if (try_module_get(drv->owner)) {
-                               drv->flags[i] = VALID_MINOR;
-                               ret = drv->cs + i;
-                       }
+               cs = drv->cs + i;
+               if (!(cs->flags & VALID_MINOR)) {
+                       cs->flags = VALID_MINOR;
+                       ret = cs;
                        break;
                }
        }
+exit:
        spin_unlock_irqrestore(&drv->lock, flags);
        return ret;
 }
 
 static void free_cs(struct cardstate *cs)
 {
-       unsigned long flags;
-       struct gigaset_driver *drv = cs->driver;
-       spin_lock_irqsave(&drv->lock, flags);
-       if (drv->flags[cs->minor_index] & VALID_MINOR)
-               module_put(drv->owner);
-       drv->flags[cs->minor_index] = 0;
-       spin_unlock_irqrestore(&drv->lock, flags);
+       cs->flags = 0;
 }
 
 static void make_valid(struct cardstate *cs, unsigned mask)
@@ -388,7 +385,7 @@ static void make_valid(struct cardstate *cs, unsigned mask)
        unsigned long flags;
        struct gigaset_driver *drv = cs->driver;
        spin_lock_irqsave(&drv->lock, flags);
-       drv->flags[cs->minor_index] |= mask;
+       cs->flags |= mask;
        spin_unlock_irqrestore(&drv->lock, flags);
 }
 
@@ -397,7 +394,7 @@ static void make_invalid(struct cardstate *cs, unsigned mask)
        unsigned long flags;
        struct gigaset_driver *drv = cs->driver;
        spin_lock_irqsave(&drv->lock, flags);
-       drv->flags[cs->minor_index] &= ~mask;
+       cs->flags &= ~mask;
        spin_unlock_irqrestore(&drv->lock, flags);
 }
 
@@ -501,11 +498,11 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
                               struct cardstate *cs, int inputstate)
 /* inbuf->read must be allocated before! */
 {
-       atomic_set(&inbuf->head, 0);
-       atomic_set(&inbuf->tail, 0);
+       inbuf->head = 0;
+       inbuf->tail = 0;
        inbuf->cs = cs;
        inbuf->bcs = bcs; /*base driver: NULL*/
-       inbuf->rcvbuf = NULL; //FIXME
+       inbuf->rcvbuf = NULL;
        inbuf->inputstate = inputstate;
 }
 
@@ -521,8 +518,8 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
                return 0;
 
        bytesleft = numbytes;
-       tail = atomic_read(&inbuf->tail);
-       head = atomic_read(&inbuf->head);
+       tail = inbuf->tail;
+       head = inbuf->head;
        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
 
        while (bytesleft) {
@@ -546,7 +543,7 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
                src += n;
        }
        gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
-       atomic_set(&inbuf->tail, tail);
+       inbuf->tail = tail;
        return numbytes != bytesleft;
 }
 EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);
@@ -668,7 +665,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
 
        tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
                     (unsigned long) cs);
-       atomic_set(&cs->commands_pending, 0);
+       cs->commands_pending = 0;
        cs->cur_at_seq = 0;
        cs->gotfwver = -1;
        cs->open_count = 0;
@@ -688,8 +685,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
        init_waitqueue_head(&cs->waitqueue);
        cs->waiting = 0;
 
-       atomic_set(&cs->mode, M_UNKNOWN);
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
+       cs->mode = M_UNKNOWN;
+       cs->mstate = MS_UNINITIALIZED;
 
        for (i = 0; i < channels; ++i) {
                gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
@@ -806,8 +803,8 @@ static void cleanup_cs(struct cardstate *cs)
 
        spin_lock_irqsave(&cs->lock, flags);
 
-       atomic_set(&cs->mode, M_UNKNOWN);
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
+       cs->mode = M_UNKNOWN;
+       cs->mstate = MS_UNINITIALIZED;
 
        clear_at_state(&cs->at_state);
        dealloc_at_states(cs);
@@ -817,8 +814,8 @@ static void cleanup_cs(struct cardstate *cs)
        kfree(cs->inbuf->rcvbuf);
        cs->inbuf->rcvbuf = NULL;
        cs->inbuf->inputstate = INS_command;
-       atomic_set(&cs->inbuf->head, 0);
-       atomic_set(&cs->inbuf->tail, 0);
+       cs->inbuf->head = 0;
+       cs->inbuf->tail = 0;
 
        cb = cs->cmdbuf;
        while (cb) {
@@ -832,7 +829,7 @@ static void cleanup_cs(struct cardstate *cs)
        cs->gotfwver = -1;
        cs->dle = 0;
        cs->cur_at_seq = 0;
-       atomic_set(&cs->commands_pending, 0);
+       cs->commands_pending = 0;
        cs->cbytes = 0;
 
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -862,7 +859,7 @@ int gigaset_start(struct cardstate *cs)
        cs->connected = 1;
        spin_unlock_irqrestore(&cs->lock, flags);
 
-       if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       if (cs->mstate != MS_LOCKED) {
                cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
                cs->ops->baud_rate(cs, B115200);
                cs->ops->set_line_ctrl(cs, CS8);
@@ -893,10 +890,17 @@ error:
 }
 EXPORT_SYMBOL_GPL(gigaset_start);
 
-void gigaset_shutdown(struct cardstate *cs)
+/* gigaset_shutdown
+ * check if a device is associated to the cardstate structure and stop it
+ * return value: 0 if ok, -1 if no device was associated
+ */
+int gigaset_shutdown(struct cardstate *cs)
 {
        mutex_lock(&cs->mutex);
 
+       if (!(cs->flags & VALID_MINOR))
+               return -1;
+
        cs->waiting = 1;
 
        if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) {
@@ -913,6 +917,7 @@ void gigaset_shutdown(struct cardstate *cs)
 
 exit:
        mutex_unlock(&cs->mutex);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(gigaset_shutdown);
 
@@ -954,13 +959,11 @@ struct cardstate *gigaset_get_cs_by_id(int id)
        list_for_each_entry(drv, &drivers, list) {
                spin_lock(&drv->lock);
                for (i = 0; i < drv->minors; ++i) {
-                       if (drv->flags[i] & VALID_ID) {
-                               cs = drv->cs + i;
-                               if (cs->myid == id)
-                                       ret = cs;
-                       }
-                       if (ret)
+                       cs = drv->cs + i;
+                       if ((cs->flags & VALID_ID) && cs->myid == id) {
+                               ret = cs;
                                break;
+                       }
                }
                spin_unlock(&drv->lock);
                if (ret)
@@ -983,10 +986,9 @@ void gigaset_debugdrivers(void)
                spin_lock(&drv->lock);
                for (i = 0; i < drv->minors; ++i) {
                        gig_dbg(DEBUG_DRIVER, "  index %u", i);
-                       gig_dbg(DEBUG_DRIVER, "    flags 0x%02x",
-                               drv->flags[i]);
                        cs = drv->cs + i;
                        gig_dbg(DEBUG_DRIVER, "    cardstate %p", cs);
+                       gig_dbg(DEBUG_DRIVER, "    flags 0x%02x", cs->flags);
                        gig_dbg(DEBUG_DRIVER, "    minor_index %u",
                                cs->minor_index);
                        gig_dbg(DEBUG_DRIVER, "    driver %p", cs->driver);
@@ -1010,7 +1012,7 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
                        continue;
                index = minor - drv->minor;
                spin_lock(&drv->lock);
-               if (drv->flags[index] & VALID_MINOR)
+               if (drv->cs[index].flags & VALID_MINOR)
                        ret = drv->cs + index;
                spin_unlock(&drv->lock);
                if (ret)
@@ -1038,7 +1040,6 @@ void gigaset_freedriver(struct gigaset_driver *drv)
        gigaset_if_freedriver(drv);
 
        kfree(drv->cs);
-       kfree(drv->flags);
        kfree(drv);
 }
 EXPORT_SYMBOL_GPL(gigaset_freedriver);
@@ -1080,12 +1081,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
        if (!drv->cs)
                goto error;
 
-       drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
-       if (!drv->flags)
-               goto error;
-
        for (i = 0; i < minors; ++i) {
-               drv->flags[i] = 0;
+               drv->cs[i].flags = 0;
                drv->cs[i].driver = drv;
                drv->cs[i].ops = drv->ops;
                drv->cs[i].minor_index = i;
@@ -1106,53 +1103,9 @@ error:
 }
 EXPORT_SYMBOL_GPL(gigaset_initdriver);
 
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
-{
-       unsigned long flags;
-       struct cardstate *cs = NULL;
-       unsigned i;
-
-       spin_lock_irqsave(&drv->lock, flags);
-       if (drv->blocked)
-               goto exit;
-       for (i = 0; i < drv->minors; ++i) {
-               if ((drv->flags[i] & VALID_MINOR) &&
-                   !(drv->flags[i] & ASSIGNED)) {
-                       drv->flags[i] |= ASSIGNED;
-                       cs = drv->cs + i;
-                       break;
-               }
-       }
-exit:
-       spin_unlock_irqrestore(&drv->lock, flags);
-       return cs;
-}
-EXPORT_SYMBOL_GPL(gigaset_getunassignedcs);
-
-void gigaset_unassign(struct cardstate *cs)
-{
-       unsigned long flags;
-       unsigned *minor_flags;
-       struct gigaset_driver *drv;
-
-       if (!cs)
-               return;
-       drv = cs->driver;
-       spin_lock_irqsave(&drv->lock, flags);
-       minor_flags = drv->flags + cs->minor_index;
-       if (*minor_flags & VALID_MINOR)
-               *minor_flags &= ~ASSIGNED;
-       spin_unlock_irqrestore(&drv->lock, flags);
-}
-EXPORT_SYMBOL_GPL(gigaset_unassign);
-
 void gigaset_blockdriver(struct gigaset_driver *drv)
 {
-       unsigned long flags;
-       spin_lock_irqsave(&drv->lock, flags);
        drv->blocked = 1;
-       spin_unlock_irqrestore(&drv->lock, flags);
 }
 EXPORT_SYMBOL_GPL(gigaset_blockdriver);
 
index cec1ef3..5cbf64d 100644 (file)
@@ -735,7 +735,7 @@ static void disconnect(struct at_state_t **at_state_p)
        /* revert to selected idle mode */
        if (!cs->cidmode) {
                cs->at_state.pending_commands |= PC_UMMODE;
-               atomic_set(&cs->commands_pending, 1); //FIXME
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
        }
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -793,15 +793,15 @@ static void init_failed(struct cardstate *cs, int mode)
        struct at_state_t *at_state;
 
        cs->at_state.pending_commands &= ~PC_INIT;
-       atomic_set(&cs->mode, mode);
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
+       cs->mode = mode;
+       cs->mstate = MS_UNINITIALIZED;
        gigaset_free_channels(cs);
        for (i = 0; i < cs->channels; ++i) {
                at_state = &cs->bcs[i].at_state;
                if (at_state->pending_commands & PC_CID) {
                        at_state->pending_commands &= ~PC_CID;
                        at_state->pending_commands |= PC_NOCID;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                }
        }
 }
@@ -812,11 +812,11 @@ static void schedule_init(struct cardstate *cs, int state)
                gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again");
                return;
        }
-       atomic_set(&cs->mstate, state);
-       atomic_set(&cs->mode, M_UNKNOWN);
+       cs->mstate = state;
+       cs->mode = M_UNKNOWN;
        gigaset_block_channels(cs);
        cs->at_state.pending_commands |= PC_INIT;
-       atomic_set(&cs->commands_pending, 1);
+       cs->commands_pending = 1;
        gig_dbg(DEBUG_CMD, "Scheduling PC_INIT");
 }
 
@@ -953,13 +953,13 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind
 
        at_state->pending_commands |= PC_CID;
        gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
-       atomic_set(&cs->commands_pending, 1);
+       cs->commands_pending = 1;
        return;
 
 error:
        at_state->pending_commands |= PC_NOCID;
        gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
-       atomic_set(&cs->commands_pending, 1);
+       cs->commands_pending = 1;
        return;
 }
 
@@ -973,12 +973,12 @@ static void start_accept(struct at_state_t *at_state)
        if (retval == 0) {
                at_state->pending_commands |= PC_ACCEPT;
                gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
        } else {
-               //FIXME
+               /* error reset */
                at_state->pending_commands |= PC_HUP;
                gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
        }
 }
 
@@ -986,7 +986,7 @@ static void do_start(struct cardstate *cs)
 {
        gigaset_free_channels(cs);
 
-       if (atomic_read(&cs->mstate) != MS_LOCKED)
+       if (cs->mstate != MS_LOCKED)
                schedule_init(cs, MS_INIT);
 
        cs->isdn_up = 1;
@@ -1000,9 +1000,9 @@ static void do_start(struct cardstate *cs)
 
 static void finish_shutdown(struct cardstate *cs)
 {
-       if (atomic_read(&cs->mstate) != MS_LOCKED) {
-               atomic_set(&cs->mstate, MS_UNINITIALIZED);
-               atomic_set(&cs->mode, M_UNKNOWN);
+       if (cs->mstate != MS_LOCKED) {
+               cs->mstate = MS_UNINITIALIZED;
+               cs->mode = M_UNKNOWN;
        }
 
        /* Tell the LL that the device is not available .. */
@@ -1022,10 +1022,10 @@ static void do_shutdown(struct cardstate *cs)
 {
        gigaset_block_channels(cs);
 
-       if (atomic_read(&cs->mstate) == MS_READY) {
-               atomic_set(&cs->mstate, MS_SHUTDOWN);
+       if (cs->mstate == MS_READY) {
+               cs->mstate = MS_SHUTDOWN;
                cs->at_state.pending_commands |= PC_SHUTDOWN;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN");
        } else
                finish_shutdown(cs);
@@ -1120,7 +1120,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
                 * In fact it doesn't.
                 */
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
        }
 }
@@ -1130,7 +1130,7 @@ static int do_lock(struct cardstate *cs)
        int mode;
        int i;
 
-       switch (atomic_read(&cs->mstate)) {
+       switch (cs->mstate) {
        case MS_UNINITIALIZED:
        case MS_READY:
                if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) ||
@@ -1152,20 +1152,20 @@ static int do_lock(struct cardstate *cs)
                return -EBUSY;
        }
 
-       mode = atomic_read(&cs->mode);
-       atomic_set(&cs->mstate, MS_LOCKED);
-       atomic_set(&cs->mode, M_UNKNOWN);
+       mode = cs->mode;
+       cs->mstate = MS_LOCKED;
+       cs->mode = M_UNKNOWN;
 
        return mode;
 }
 
 static int do_unlock(struct cardstate *cs)
 {
-       if (atomic_read(&cs->mstate) != MS_LOCKED)
+       if (cs->mstate != MS_LOCKED)
                return -EINVAL;
 
-       atomic_set(&cs->mstate, MS_UNINITIALIZED);
-       atomic_set(&cs->mode, M_UNKNOWN);
+       cs->mstate = MS_UNINITIALIZED;
+       cs->mode = M_UNKNOWN;
        gigaset_free_channels(cs);
        if (cs->connected)
                schedule_init(cs, MS_INIT);
@@ -1198,17 +1198,17 @@ static void do_action(int action, struct cardstate *cs,
        case ACT_INIT:
                cs->at_state.pending_commands &= ~PC_INIT;
                cs->cur_at_seq = SEQ_NONE;
-               atomic_set(&cs->mode, M_UNIMODEM);
+               cs->mode = M_UNIMODEM;
                spin_lock_irqsave(&cs->lock, flags);
                if (!cs->cidmode) {
                        spin_unlock_irqrestore(&cs->lock, flags);
                        gigaset_free_channels(cs);
-                       atomic_set(&cs->mstate, MS_READY);
+                       cs->mstate = MS_READY;
                        break;
                }
                spin_unlock_irqrestore(&cs->lock, flags);
                cs->at_state.pending_commands |= PC_CIDMODE;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
                break;
        case ACT_FAILINIT:
@@ -1234,22 +1234,20 @@ static void do_action(int action, struct cardstate *cs,
                        | INS_command;
                break;
        case ACT_CMODESET:
-               if (atomic_read(&cs->mstate) == MS_INIT ||
-                   atomic_read(&cs->mstate) == MS_RECOVER) {
+               if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
                        gigaset_free_channels(cs);
-                       atomic_set(&cs->mstate, MS_READY);
+                       cs->mstate = MS_READY;
                }
-               atomic_set(&cs->mode, M_CID);
+               cs->mode = M_CID;
                cs->cur_at_seq = SEQ_NONE;
                break;
        case ACT_UMODESET:
-               atomic_set(&cs->mode, M_UNIMODEM);
+               cs->mode = M_UNIMODEM;
                cs->cur_at_seq = SEQ_NONE;
                break;
        case ACT_FAILCMODE:
                cs->cur_at_seq = SEQ_NONE;
-               if (atomic_read(&cs->mstate) == MS_INIT ||
-                   atomic_read(&cs->mstate) == MS_RECOVER) {
+               if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) {
                        init_failed(cs, M_UNKNOWN);
                        break;
                }
@@ -1307,7 +1305,7 @@ static void do_action(int action, struct cardstate *cs,
        case ACT_CONNECT:
                if (cs->onechannel) {
                        at_state->pending_commands |= PC_DLE1;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                        break;
                }
                bcs->chstate |= CHS_D_UP;
@@ -1333,7 +1331,7 @@ static void do_action(int action, struct cardstate *cs,
                         * DLE only used for M10x with one B channel.
                         */
                        at_state->pending_commands |= PC_DLE0;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                } else
                        disconnect(p_at_state);
                break;
@@ -1369,7 +1367,7 @@ static void do_action(int action, struct cardstate *cs,
                         "Could not enter DLE mode. Trying to hang up.\n");
                channel = cs->curchannel;
                cs->bcs[channel].at_state.pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
 
        case ACT_CID: /* got cid; start dialing */
@@ -1379,7 +1377,7 @@ static void do_action(int action, struct cardstate *cs,
                        cs->bcs[channel].at_state.cid = ev->parameter;
                        cs->bcs[channel].at_state.pending_commands |=
                                PC_DIAL;
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                        break;
                }
                /* fall through */
@@ -1411,14 +1409,14 @@ static void do_action(int action, struct cardstate *cs,
        case ACT_ABORTDIAL:     /* error/timeout during dial preparation */
                cs->cur_at_seq = SEQ_NONE;
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
 
        case ACT_REMOTEREJECT:  /* DISCONNECT_IND after dialling */
        case ACT_CONNTIMEOUT:   /* timeout waiting for ZSAU=ACTIVE */
        case ACT_REMOTEHUP:     /* DISCONNECT_IND with established connection */
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                break;
        case ACT_GETSTRING: /* warning: RING, ZDLE, ...
                               are not handled properly anymore */
@@ -1515,7 +1513,7 @@ static void do_action(int action, struct cardstate *cs,
                break;
        case ACT_HUP:
                at_state->pending_commands |= PC_HUP;
-               atomic_set(&cs->commands_pending, 1);
+               cs->commands_pending = 1;
                gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
                break;
 
@@ -1558,7 +1556,7 @@ static void do_action(int action, struct cardstate *cs,
                                cs->at_state.pending_commands |= PC_UMMODE;
                                gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
                        }
-                       atomic_set(&cs->commands_pending, 1);
+                       cs->commands_pending = 1;
                }
                spin_unlock_irqrestore(&cs->lock, flags);
                cs->waiting = 0;
@@ -1741,7 +1739,7 @@ static void process_command_flags(struct cardstate *cs)
        int sequence;
        unsigned long flags;
 
-       atomic_set(&cs->commands_pending, 0);
+       cs->commands_pending = 0;
 
        if (cs->cur_at_seq) {
                gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy");
@@ -1779,7 +1777,7 @@ static void process_command_flags(struct cardstate *cs)
                                ~(PC_DLE1 | PC_ACCEPT | PC_DIAL);
                        if (at_state->cid > 0)
                                at_state->pending_commands |= PC_HUP;
-                       if (atomic_read(&cs->mstate) == MS_RECOVER) {
+                       if (cs->mstate == MS_RECOVER) {
                                if (at_state->pending_commands & PC_CID) {
                                        at_state->pending_commands |= PC_NOCID;
                                        at_state->pending_commands &= ~PC_CID;
@@ -1793,7 +1791,7 @@ static void process_command_flags(struct cardstate *cs)
        if (cs->at_state.pending_commands == PC_UMMODE
            && !cs->cidmode
            && list_empty(&cs->temp_at_states)
-           && atomic_read(&cs->mode) == M_CID) {
+           && cs->mode == M_CID) {
                sequence = SEQ_UMMODE;
                at_state = &cs->at_state;
                for (i = 0; i < cs->channels; ++i) {
@@ -1860,7 +1858,7 @@ static void process_command_flags(struct cardstate *cs)
        }
        if (cs->at_state.pending_commands & PC_CIDMODE) {
                cs->at_state.pending_commands &= ~PC_CIDMODE;
-               if (atomic_read(&cs->mode) == M_UNIMODEM) {
+               if (cs->mode == M_UNIMODEM) {
                        cs->retry_count = 1;
                        schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE);
                        return;
@@ -1886,11 +1884,11 @@ static void process_command_flags(struct cardstate *cs)
                        return;
                }
                if (bcs->at_state.pending_commands & PC_CID) {
-                       switch (atomic_read(&cs->mode)) {
+                       switch (cs->mode) {
                        case M_UNIMODEM:
                                cs->at_state.pending_commands |= PC_CIDMODE;
                                gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
-                               atomic_set(&cs->commands_pending, 1);
+                               cs->commands_pending = 1;
                                return;
 #ifdef GIG_MAYINITONDIAL
                        case M_UNKNOWN:
@@ -1926,7 +1924,7 @@ static void process_events(struct cardstate *cs)
        for (i = 0; i < 2 * MAX_EVENTS; ++i) {
                tail = cs->ev_tail;
                if (tail == head) {
-                       if (!check_flags && !atomic_read(&cs->commands_pending))
+                       if (!check_flags && !cs->commands_pending)
                                break;
                        check_flags = 0;
                        spin_unlock_irqrestore(&cs->ev_lock, flags);
@@ -1934,7 +1932,7 @@ static void process_events(struct cardstate *cs)
                        spin_lock_irqsave(&cs->ev_lock, flags);
                        tail = cs->ev_tail;
                        if (tail == head) {
-                               if (!atomic_read(&cs->commands_pending))
+                               if (!cs->commands_pending)
                                        break;
                                continue;
                        }
@@ -1971,7 +1969,7 @@ void gigaset_handle_event(unsigned long data)
        struct cardstate *cs = (struct cardstate *) data;
 
        /* handle incoming data on control/common channel */
-       if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) {
+       if (cs->inbuf->head != cs->inbuf->tail) {
                gig_dbg(DEBUG_INTR, "processing new data");
                cs->ops->handle_input(cs->inbuf);
        }
index 02bdaf2..f365993 100644 (file)
 
 extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
 
-/* any combination of these can be given with the 'debug=' parameter to insmod,
- * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and
- * DEBUG_INTR.
- */
+/* debug flags, combine by adding/bitwise OR */
 enum debuglevel {
-       DEBUG_REG         = 0x0002, /* serial port I/O register operations */
-       DEBUG_OPEN        = 0x0004, /* open/close serial port */
-       DEBUG_INTR        = 0x0008, /* interrupt processing */
-       DEBUG_INTR_DUMP   = 0x0010, /* Activating hexdump debug output on
-                                      interrupt requests, not available as
-                                      run-time option */
+       DEBUG_INTR        = 0x00008, /* interrupt processing */
        DEBUG_CMD         = 0x00020, /* sent/received LL commands */
        DEBUG_STREAM      = 0x00040, /* application data stream I/O events */
        DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
        DEBUG_LLDATA      = 0x00100, /* sent/received LL data */
-       DEBUG_INTR_0      = 0x00200, /* serial port interrupt processing */
        DEBUG_DRIVER      = 0x00400, /* driver structure */
        DEBUG_HDLC        = 0x00800, /* M10x HDLC processing */
        DEBUG_WRITE       = 0x01000, /* M105 data write */
@@ -93,7 +84,7 @@ enum debuglevel {
        DEBUG_MCMD        = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */
        DEBUG_INIT        = 0x08000, /* (de)allocation+initialization of data
                                        structures */
-       DEBUG_LOCK        = 0x10000, /* semaphore operations */
+       DEBUG_SUSPEND     = 0x10000, /* suspend/resume processing */
        DEBUG_OUTPUT      = 0x20000, /* output to device */
        DEBUG_ISO         = 0x40000, /* isochronous transfers */
        DEBUG_IF          = 0x80000, /* character device operations */
@@ -191,6 +182,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
 #define        HD_OPEN_ATCHANNEL               (0x28)          // 3070
 #define        HD_CLOSE_ATCHANNEL              (0x29)          // 3070
 
+/* number of B channels supported by base driver */
+#define BAS_CHANNELS   2
+
 /* USB frames for isochronous transfer */
 #define BAS_FRAMETIME  1       /* number of milliseconds between frames */
 #define BAS_NUMFRAMES  8       /* number of frames per URB */
@@ -313,7 +307,7 @@ struct inbuf_t {
        struct bc_state         *bcs;
        struct cardstate        *cs;
        int                     inputstate;
-       atomic_t                head, tail;
+       int                     head, tail;
        unsigned char           data[RBUFSIZE];
 };
 
@@ -335,9 +329,9 @@ struct inbuf_t {
  *   are also filled with that value
  */
 struct isowbuf_t {
-       atomic_t        read;
-       atomic_t        nextread;
-       atomic_t        write;
+       int             read;
+       int             nextread;
+       int             write;
        atomic_t        writesem;
        int             wbits;
        unsigned char   data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD];
@@ -350,11 +344,13 @@ struct isowbuf_t {
  * - urb: pointer to the URB itself
  * - bcs: pointer to the B Channel control structure
  * - limit: end of write buffer area covered by this URB
+ * - status: URB completion status
  */
 struct isow_urbctx_t {
        struct urb *urb;
        struct bc_state *bcs;
        int limit;
+       int status;
 };
 
 /* AT state structure
@@ -439,14 +435,15 @@ struct cardstate {
        unsigned minor_index;
        struct device *dev;
        struct device *tty_dev;
+       unsigned flags;
 
        const struct gigaset_ops *ops;
 
        /* Stuff to handle communication */
        wait_queue_head_t waitqueue;
        int waiting;
-       atomic_t mode;                  /* see M_XXXX */
-       atomic_t mstate;                /* Modem state: see MS_XXXX */
+       int mode;                       /* see M_XXXX */
+       int mstate;                     /* Modem state: see MS_XXXX */
                                        /* only changed by the event layer */
        int cmd_result;
 
@@ -503,7 +500,7 @@ struct cardstate {
                                           processed */
        int curchannel;                 /* channel those commands are meant
                                           for */
-       atomic_t commands_pending;      /* flag(s) in xxx.commands_pending have
+       int commands_pending;           /* flag(s) in xxx.commands_pending have
                                           been set */
        struct tasklet_struct event_tasklet;
                                        /* tasklet for serializing AT commands.
@@ -543,7 +540,6 @@ struct gigaset_driver {
        unsigned minor;
        unsigned minors;
        struct cardstate *cs;
-       unsigned *flags;
        int blocked;
 
        const struct gigaset_ops *ops;
@@ -559,7 +555,7 @@ struct cmdbuf_t {
 
 struct bas_bc_state {
        /* isochronous output state */
-       atomic_t        running;
+       int             running;
        atomic_t        corrbytes;
        spinlock_t      isooutlock;
        struct isow_urbctx_t    isoouturbs[BAS_OUTURBS];
@@ -574,6 +570,7 @@ struct bas_bc_state {
        struct urb *isoinurbs[BAS_INURBS];
        unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
        struct urb *isoindone;          /* completed isoc read URB */
+       int isoinstatus;                /* status of completed URB */
        int loststatus;                 /* status of dropped URB */
        unsigned isoinlost;             /* number of bytes lost */
        /* state of bit unstuffing algorithm
@@ -770,10 +767,6 @@ void gigaset_freedriver(struct gigaset_driver *drv);
 void gigaset_debugdrivers(void);
 struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
 struct cardstate *gigaset_get_cs_by_id(int id);
-
-/* For drivers without fixed assignment device<->cardstate (usb) */
-struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
-void gigaset_unassign(struct cardstate *cs);
 void gigaset_blockdriver(struct gigaset_driver *drv);
 
 /* Allocate and initialize card state. Calls hardware dependent
@@ -792,7 +785,7 @@ int gigaset_start(struct cardstate *cs);
 void gigaset_stop(struct cardstate *cs);
 
 /* Tell common.c that the driver is being unloaded. */
-void gigaset_shutdown(struct cardstate *cs);
+int gigaset_shutdown(struct cardstate *cs);
 
 /* Tell common.c that an skb has been sent. */
 void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
index eb50f3d..af195b0 100644 (file)
@@ -28,12 +28,11 @@ static int if_lock(struct cardstate *cs, int *arg)
                return -EINVAL;
 
        if (cmd < 0) {
-               *arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove?
+               *arg = cs->mstate == MS_LOCKED;
                return 0;
        }
 
-       if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
-           && cs->connected) {
+       if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
                cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
                cs->ops->baud_rate(cs, B115200);
                cs->ops->set_line_ctrl(cs, CS8);
@@ -104,7 +103,7 @@ static int if_config(struct cardstate *cs, int *arg)
        if (*arg != 1)
                return -EINVAL;
 
-       if (atomic_read(&cs->mstate) != MS_LOCKED)
+       if (cs->mstate != MS_LOCKED)
                return -EBUSY;
 
        if (!cs->connected) {
@@ -162,7 +161,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
        tty->driver_data = NULL;
 
        cs = gigaset_get_cs_by_tty(tty);
-       if (!cs)
+       if (!cs || !try_module_get(cs->driver->owner))
                return -ENODEV;
 
        if (mutex_lock_interruptible(&cs->mutex))
@@ -208,6 +207,8 @@ static void if_close(struct tty_struct *tty, struct file *filp)
        }
 
        mutex_unlock(&cs->mutex);
+
+       module_put(cs->driver->owner);
 }
 
 static int if_ioctl(struct tty_struct *tty, struct file *file,
@@ -364,7 +365,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
 
        if (!cs->open_count)
                warn("%s: device not opened", __func__);
-       else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       else if (cs->mstate != MS_LOCKED) {
                warn("can't write to unlocked device");
                retval = -EBUSY;
        } else if (!cs->connected) {
@@ -398,9 +399,9 @@ static int if_write_room(struct tty_struct *tty)
 
        if (!cs->open_count)
                warn("%s: device not opened", __func__);
-       else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       else if (cs->mstate != MS_LOCKED) {
                warn("can't write to unlocked device");
-               retval = -EBUSY; //FIXME
+               retval = -EBUSY;
        } else if (!cs->connected) {
                gig_dbg(DEBUG_ANY, "can't write to unplugged device");
                retval = -EBUSY; //FIXME
@@ -430,7 +431,7 @@ static int if_chars_in_buffer(struct tty_struct *tty)
 
        if (!cs->open_count)
                warn("%s: device not opened", __func__);
-       else if (atomic_read(&cs->mstate) != MS_LOCKED) {
+       else if (cs->mstate != MS_LOCKED) {
                warn("can't write to unlocked device");
                retval = -EBUSY;
        } else if (!cs->connected) {
index e0505f2..e30a777 100644 (file)
@@ -23,9 +23,9 @@
  */
 void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
 {
-       atomic_set(&iwb->read, 0);
-       atomic_set(&iwb->nextread, 0);
-       atomic_set(&iwb->write, 0);
+       iwb->read = 0;
+       iwb->nextread = 0;
+       iwb->write = 0;
        atomic_set(&iwb->writesem, 1);
        iwb->wbits = 0;
        iwb->idle = idle;
@@ -39,8 +39,8 @@ static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
 {
        int read, write, freebytes;
 
-       read = atomic_read(&iwb->read);
-       write = atomic_read(&iwb->write);
+       read = iwb->read;
+       write = iwb->write;
        if ((freebytes = read - write) > 0) {
                /* no wraparound: need padding space within regular area */
                return freebytes - BAS_OUTBUFPAD;
@@ -62,7 +62,7 @@ static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
        int read;
        if (a == b)
                return 0;
-       read = atomic_read(&iwb->read);
+       read = iwb->read;
        if (a < b) {
                if (a < read && read <= b)
                        return +1;
@@ -91,18 +91,18 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
 #ifdef CONFIG_GIGASET_DEBUG
        gig_dbg(DEBUG_ISO,
                "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
-               __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
+               __func__, iwb->data[iwb->write], iwb->wbits);
 #endif
        return 1;
 }
 
 /* finish writing
- * release the write semaphore and update the maximum buffer fill level
+ * release the write semaphore
  * returns the current write position
  */
 static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
 {
-       int write = atomic_read(&iwb->write);
+       int write = iwb->write;
        atomic_inc(&iwb->writesem);
        return write;
 }
@@ -116,7 +116,7 @@ static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
  */
 static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
 {
-       int write = atomic_read(&iwb->write);
+       int write = iwb->write;
        data <<= iwb->wbits;
        data |= iwb->data[write];
        nbits += iwb->wbits;
@@ -128,7 +128,7 @@ static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
        }
        iwb->wbits = nbits;
        iwb->data[write] = data & 0xff;
-       atomic_set(&iwb->write, write);
+       iwb->write = write;
 }
 
 /* put final flag on HDLC bitstream
@@ -142,7 +142,7 @@ static inline void isowbuf_putflag(struct isowbuf_t *iwb)
        /* add two flags, thus reliably covering one byte */
        isowbuf_putbits(iwb, 0x7e7e, 8);
        /* recover the idle flag byte */
-       write = atomic_read(&iwb->write);
+       write = iwb->write;
        iwb->idle = iwb->data[write];
        gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
        /* mask extraneous bits in buffer */
@@ -160,8 +160,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
        int read, write, limit, src, dst;
        unsigned char pbyte;
 
-       read = atomic_read(&iwb->nextread);
-       write = atomic_read(&iwb->write);
+       read = iwb->nextread;
+       write = iwb->write;
        if (likely(read == write)) {
                /* return idle frame */
                return read < BAS_OUTBUFPAD ?
@@ -176,7 +176,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                err("invalid size %d", size);
                return -EINVAL;
        }
-       src = atomic_read(&iwb->read);
+       src = iwb->read;
        if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
                     (read < src && limit >= src))) {
                err("isoc write buffer frame reservation violated");
@@ -191,7 +191,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                        if (!isowbuf_startwrite(iwb))
                                return -EBUSY;
                        /* write position could have changed */
-                       if (limit >= (write = atomic_read(&iwb->write))) {
+                       write = iwb->write;
+                       if (limit >= write) {
                                pbyte = iwb->data[write]; /* save
                                                             partial byte */
                                limit = write + BAS_OUTBUFPAD;
@@ -213,7 +214,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                                        __func__, pbyte, limit);
                                iwb->data[limit] = pbyte; /* restore
                                                             partial byte */
-                               atomic_set(&iwb->write, limit);
+                               iwb->write = limit;
                        }
                        isowbuf_donewrite(iwb);
                }
@@ -233,7 +234,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
                        limit = src;
                }
        }
-       atomic_set(&iwb->nextread, limit);
+       iwb->nextread = limit;
        return read;
 }
 
@@ -477,7 +478,7 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
        unsigned char c;
 
        if (unlikely(count <= 0))
-               return atomic_read(&iwb->write); /* better ideas? */
+               return iwb->write;
 
        if (isowbuf_freebytes(iwb) < count ||
            !isowbuf_startwrite(iwb)) {
@@ -486,13 +487,13 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
        }
 
        gig_dbg(DEBUG_STREAM, "put %d bytes", count);
-       write = atomic_read(&iwb->write);
+       write = iwb->write;
        do {
                c = bitrev8(*in++);
                iwb->data[write++] = c;
                write %= BAS_OUTBUFSIZE;
        } while (--count > 0);
-       atomic_set(&iwb->write, write);
+       iwb->write = write;
        iwb->idle = c;
 
        return isowbuf_donewrite(iwb);
@@ -947,8 +948,8 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
        unsigned tail, head, numbytes;
        unsigned char *src;
 
-       head = atomic_read(&inbuf->head);
-       while (head != (tail = atomic_read(&inbuf->tail))) {
+       head = inbuf->head;
+       while (head != (tail = inbuf->tail)) {
                gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
                if (head > tail)
                        tail = RBUFSIZE;
@@ -956,7 +957,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
                numbytes = tail - head;
                gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
 
-               if (atomic_read(&cs->mstate) == MS_LOCKED) {
+               if (cs->mstate == MS_LOCKED) {
                        gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
                                           numbytes, src);
                        gigaset_if_receive(inbuf->cs, src, numbytes);
@@ -970,7 +971,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
                if (head == RBUFSIZE)
                        head = 0;
                gig_dbg(DEBUG_INTR, "setting head to %u", head);
-               atomic_set(&inbuf->head, head);
+               inbuf->head = head;
        }
 }
 
index ea44302..fceeb1d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/poll.h>
+#include <linux/completion.h>
 
 /* Version Information */
 #define DRIVER_AUTHOR "Tilman Schmidt"
@@ -48,7 +49,7 @@ struct ser_cardstate {
        struct platform_device  dev;
        struct tty_struct       *tty;
        atomic_t                refcnt;
-       struct mutex            dead_mutex;
+       struct completion       dead_cmp;
 };
 
 static struct platform_driver device_driver = {
@@ -240,7 +241,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        struct cmdbuf_t *cb;
        unsigned long flags;
 
-       gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+       gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
@@ -498,7 +499,7 @@ static struct cardstate *cs_get(struct tty_struct *tty)
 static void cs_put(struct cardstate *cs)
 {
        if (atomic_dec_and_test(&cs->hw.ser->refcnt))
-               mutex_unlock(&cs->hw.ser->dead_mutex);
+               complete(&cs->hw.ser->dead_cmp);
 }
 
 /*
@@ -527,8 +528,8 @@ gigaset_tty_open(struct tty_struct *tty)
 
        cs->dev = &cs->hw.ser->dev.dev;
        cs->hw.ser->tty = tty;
-       mutex_init(&cs->hw.ser->dead_mutex);
        atomic_set(&cs->hw.ser->refcnt, 1);
+       init_completion(&cs->hw.ser->dead_cmp);
 
        tty->disc_data = cs;
 
@@ -536,14 +537,13 @@ gigaset_tty_open(struct tty_struct *tty)
         * startup system and notify the LL that we are ready to run
         */
        if (startmode == SM_LOCKED)
-               atomic_set(&cs->mstate, MS_LOCKED);
+               cs->mstate = MS_LOCKED;
        if (!gigaset_start(cs)) {
                tasklet_kill(&cs->write_tasklet);
                goto error;
        }
 
        gig_dbg(DEBUG_INIT, "Startup of HLL done");
-       mutex_lock(&cs->hw.ser->dead_mutex);
        return 0;
 
 error:
@@ -577,7 +577,7 @@ gigaset_tty_close(struct tty_struct *tty)
        else {
                /* wait for running methods to finish */
                if (!atomic_dec_and_test(&cs->hw.ser->refcnt))
-                       mutex_lock(&cs->hw.ser->dead_mutex);
+                       wait_for_completion(&cs->hw.ser->dead_cmp);
        }
 
        /* stop operations */
@@ -714,8 +714,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
                return;
        }
 
-       tail = atomic_read(&inbuf->tail);
-       head = atomic_read(&inbuf->head);
+       tail = inbuf->tail;
+       head = inbuf->head;
        gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes",
                head, tail, count);
 
@@ -742,7 +742,7 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        }
 
        gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
-       atomic_set(&inbuf->tail, tail);
+       inbuf->tail = tail;
 
        /* Everything was received .. Push data into handler */
        gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
index ca4bee1..77d20ab 100644 (file)
@@ -104,12 +104,17 @@ MODULE_DEVICE_TABLE(usb, gigaset_table);
  * flags per packet.
  */
 
+/* functions called if a device of this driver is connected/disconnected */
 static int gigaset_probe(struct usb_interface *interface,
                         const struct usb_device_id *id);
 static void gigaset_disconnect(struct usb_interface *interface);
 
+/* functions called before/after suspend */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
+static int gigaset_resume(struct usb_interface *intf);
+static int gigaset_pre_reset(struct usb_interface *intf);
+
 static struct gigaset_driver *driver = NULL;
-static struct cardstate *cardstate = NULL;
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver gigaset_usb_driver = {
@@ -117,12 +122,17 @@ static struct usb_driver gigaset_usb_driver = {
        .probe =        gigaset_probe,
        .disconnect =   gigaset_disconnect,
        .id_table =     gigaset_table,
+       .suspend =      gigaset_suspend,
+       .resume =       gigaset_resume,
+       .reset_resume = gigaset_resume,
+       .pre_reset =    gigaset_pre_reset,
+       .post_reset =   gigaset_resume,
 };
 
 struct usb_cardstate {
        struct usb_device       *udev;          /* usb device pointer */
        struct usb_interface    *interface;     /* interface for this device */
-       atomic_t                busy;           /* bulk output in progress */
+       int                     busy;           /* bulk output in progress */
 
        /* Output buffer */
        unsigned char           *bulk_out_buffer;
@@ -314,7 +324,7 @@ static void gigaset_modem_fill(unsigned long data)
 
        gig_dbg(DEBUG_OUTPUT, "modem_fill");
 
-       if (atomic_read(&cs->hw.usb->busy)) {
+       if (cs->hw.usb->busy) {
                gig_dbg(DEBUG_OUTPUT, "modem_fill: busy");
                return;
        }
@@ -361,18 +371,13 @@ static void gigaset_read_int_callback(struct urb *urb)
 {
        struct inbuf_t *inbuf = urb->context;
        struct cardstate *cs = inbuf->cs;
-       int resubmit = 0;
+       int status = urb->status;
        int r;
        unsigned numbytes;
        unsigned char *src;
        unsigned long flags;
 
-       if (!urb->status) {
-               if (!cs->connected) {
-                       err("%s: disconnected", __func__); /* should never happen */
-                       return;
-               }
-
+       if (!status) {
                numbytes = urb->actual_length;
 
                if (numbytes) {
@@ -389,28 +394,26 @@ static void gigaset_read_int_callback(struct urb *urb)
                        }
                } else
                        gig_dbg(DEBUG_INTR, "Received zero block length");
-               resubmit = 1;
        } else {
                /* The urb might have been killed. */
-               gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
-                       __func__, urb->status);
-               if (urb->status != -ENOENT) { /* not killed */
-                       if (!cs->connected) {
-                               err("%s: disconnected", __func__); /* should never happen */
-                               return;
-                       }
-                       resubmit = 1;
-               }
+               gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d",
+                       __func__, status);
+               if (status == -ENOENT || status == -ESHUTDOWN)
+                       /* killed or endpoint shutdown: don't resubmit */
+                       return;
        }
 
-       if (resubmit) {
-               spin_lock_irqsave(&cs->lock, flags);
-               r = cs->connected ? usb_submit_urb(urb, GFP_ATOMIC) : -ENODEV;
+       /* resubmit URB */
+       spin_lock_irqsave(&cs->lock, flags);
+       if (!cs->connected) {
                spin_unlock_irqrestore(&cs->lock, flags);
-               if (r)
-                       dev_err(cs->dev, "error %d when resubmitting urb.\n",
-                               -r);
+               err("%s: disconnected", __func__);
+               return;
        }
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       spin_unlock_irqrestore(&cs->lock, flags);
+       if (r)
+               dev_err(cs->dev, "error %d resubmitting URB\n", -r);
 }
 
 
@@ -418,19 +421,28 @@ static void gigaset_read_int_callback(struct urb *urb)
 static void gigaset_write_bulk_callback(struct urb *urb)
 {
        struct cardstate *cs = urb->context;
+       int status = urb->status;
        unsigned long flags;
 
-       if (urb->status)
+       switch (status) {
+       case 0:                 /* normal completion */
+               break;
+       case -ENOENT:           /* killed */
+               gig_dbg(DEBUG_ANY, "%s: killed", __func__);
+               cs->hw.usb->busy = 0;
+               return;
+       default:
                dev_err(cs->dev, "bulk transfer failed (status %d)\n",
-                       -urb->status);
+                       -status);
                /* That's all we can do. Communication problems
                   are handled by timeouts or network protocols. */
+       }
 
        spin_lock_irqsave(&cs->lock, flags);
        if (!cs->connected) {
                err("%s: not connected", __func__);
        } else {
-               atomic_set(&cs->hw.usb->busy, 0);
+               cs->hw.usb->busy = 0;
                tasklet_schedule(&cs->write_tasklet);
        }
        spin_unlock_irqrestore(&cs->lock, flags);
@@ -478,14 +490,14 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
 
                        cb->offset += count;
                        cb->len -= count;
-                       atomic_set(&ucs->busy, 1);
+                       ucs->busy = 1;
 
                        spin_lock_irqsave(&cs->lock, flags);
                        status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV;
                        spin_unlock_irqrestore(&cs->lock, flags);
 
                        if (status) {
-                               atomic_set(&ucs->busy, 0);
+                               ucs->busy = 0;
                                err("could not submit urb (error %d)\n",
                                    -status);
                                cb->len = 0; /* skip urb => remove cb+wakeup
@@ -504,7 +516,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        struct cmdbuf_t *cb;
        unsigned long flags;
 
-       gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+       gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
                           "CMD Transmit", len, buf);
 
@@ -641,7 +653,7 @@ static int write_modem(struct cardstate *cs)
        count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
        skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
        skb_pull(bcs->tx_skb, count);
-       atomic_set(&ucs->busy, 1);
+       ucs->busy = 1;
        gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
 
        spin_lock_irqsave(&cs->lock, flags);
@@ -659,7 +671,7 @@ static int write_modem(struct cardstate *cs)
 
        if (ret) {
                err("could not submit urb (error %d)\n", -ret);
-               atomic_set(&ucs->busy, 0);
+               ucs->busy = 0;
        }
 
        if (!bcs->tx_skb->len) {
@@ -680,53 +692,44 @@ static int gigaset_probe(struct usb_interface *interface,
 {
        int retval;
        struct usb_device *udev = interface_to_usbdev(interface);
-       unsigned int ifnum;
-       struct usb_host_interface *hostif;
+       struct usb_host_interface *hostif = interface->cur_altsetting;
        struct cardstate *cs = NULL;
        struct usb_cardstate *ucs = NULL;
        struct usb_endpoint_descriptor *endpoint;
        int buffer_size;
-       int alt;
 
-       gig_dbg(DEBUG_ANY,
-               "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
-               __func__, le16_to_cpu(udev->descriptor.idVendor),
-               le16_to_cpu(udev->descriptor.idProduct));
-
-       retval = -ENODEV; //FIXME
+       gig_dbg(DEBUG_ANY, "%s: Check if device matches ...", __func__);
 
        /* See if the device offered us matches what we can accept */
        if ((le16_to_cpu(udev->descriptor.idVendor)  != USB_M105_VENDOR_ID) ||
-           (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID))
+           (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) {
+               gig_dbg(DEBUG_ANY, "device ID (0x%x, 0x%x) not for me - skip",
+                       le16_to_cpu(udev->descriptor.idVendor),
+                       le16_to_cpu(udev->descriptor.idProduct));
                return -ENODEV;
-
-       /* this starts to become ascii art... */
-       hostif = interface->cur_altsetting;
-       alt = hostif->desc.bAlternateSetting;
-       ifnum = hostif->desc.bInterfaceNumber; // FIXME ?
-
-       if (alt != 0 || ifnum != 0) {
-               dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt);
+       }
+       if (hostif->desc.bInterfaceNumber != 0) {
+               gig_dbg(DEBUG_ANY, "interface %d not for me - skip",
+                       hostif->desc.bInterfaceNumber);
+               return -ENODEV;
+       }
+       if (hostif->desc.bAlternateSetting != 0) {
+               dev_notice(&udev->dev, "unsupported altsetting %d - skip",
+                          hostif->desc.bAlternateSetting);
                return -ENODEV;
        }
-
-       /* Reject application specific intefaces
-        *
-        */
        if (hostif->desc.bInterfaceClass != 255) {
-               dev_info(&udev->dev,
-               "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n",
-                        __func__, ifnum, hostif->desc.bInterfaceClass);
+               dev_notice(&udev->dev, "unsupported interface class %d - skip",
+                          hostif->desc.bInterfaceClass);
                return -ENODEV;
        }
 
        dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
 
-       cs = gigaset_getunassignedcs(driver);
-       if (!cs) {
-               dev_warn(&udev->dev, "no free cardstate\n");
+       /* allocate memory for our device state and intialize it */
+       cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
+       if (!cs)
                return -ENODEV;
-       }
        ucs = cs->hw.usb;
 
        /* save off device structure ptrs for later use */
@@ -759,7 +762,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        endpoint = &hostif->endpoint[1].desc;
 
-       atomic_set(&ucs->busy, 0);
+       ucs->busy = 0;
 
        ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!ucs->read_urb) {
@@ -792,7 +795,7 @@ static int gigaset_probe(struct usb_interface *interface,
 
        /* tell common part that the device is ready */
        if (startmode == SM_LOCKED)
-               atomic_set(&cs->mstate, MS_LOCKED);
+               cs->mstate = MS_LOCKED;
 
        if (!gigaset_start(cs)) {
                tasklet_kill(&cs->write_tasklet);
@@ -813,7 +816,7 @@ error:
        usb_put_dev(ucs->udev);
        ucs->udev = NULL;
        ucs->interface = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
        return retval;
 }
 
@@ -824,6 +827,9 @@ static void gigaset_disconnect(struct usb_interface *interface)
 
        cs = usb_get_intfdata(interface);
        ucs = cs->hw.usb;
+
+       dev_info(cs->dev, "disconnecting Gigaset USB adapter\n");
+
        usb_kill_urb(ucs->read_urb);
 
        gigaset_stop(cs);
@@ -831,7 +837,7 @@ static void gigaset_disconnect(struct usb_interface *interface)
        usb_set_intfdata(interface, NULL);
        tasklet_kill(&cs->write_tasklet);
 
-       usb_kill_urb(ucs->bulk_out_urb);        /* FIXME: only if active? */
+       usb_kill_urb(ucs->bulk_out_urb);
 
        kfree(ucs->bulk_out_buffer);
        usb_free_urb(ucs->bulk_out_urb);
@@ -844,7 +850,53 @@ static void gigaset_disconnect(struct usb_interface *interface)
        ucs->interface = NULL;
        ucs->udev = NULL;
        cs->dev = NULL;
-       gigaset_unassign(cs);
+       gigaset_freecs(cs);
+}
+
+/* gigaset_suspend
+ * This function is called before the USB connection is suspended or reset.
+ */
+static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+
+       /* stop activity */
+       cs->connected = 0;      /* prevent rescheduling */
+       usb_kill_urb(cs->hw.usb->read_urb);
+       tasklet_kill(&cs->write_tasklet);
+       usb_kill_urb(cs->hw.usb->bulk_out_urb);
+
+       gig_dbg(DEBUG_SUSPEND, "suspend complete");
+       return 0;
+}
+
+/* gigaset_resume
+ * This function is called after the USB connection has been resumed or reset.
+ */
+static int gigaset_resume(struct usb_interface *intf)
+{
+       struct cardstate *cs = usb_get_intfdata(intf);
+       int rc;
+
+       /* resubmit interrupt URB */
+       cs->connected = 1;
+       rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL);
+       if (rc) {
+               dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc);
+               return rc;
+       }
+
+       gig_dbg(DEBUG_SUSPEND, "resume complete");
+       return 0;
+}
+
+/* gigaset_pre_reset
+ * This function is called before the USB connection is reset.
+ */
+static int gigaset_pre_reset(struct usb_interface *intf)
+{
+       /* same as suspend */
+       return gigaset_suspend(intf, PMSG_ON);
 }
 
 static const struct gigaset_ops ops = {
@@ -880,11 +932,6 @@ static int __init usb_gigaset_init(void)
                                       &ops, THIS_MODULE)) == NULL)
                goto error;
 
-       /* allocate memory for our device state and intialize it */
-       cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME);
-       if (!cardstate)
-               goto error;
-
        /* register this driver with the USB subsystem */
        result = usb_register(&gigaset_usb_driver);
        if (result < 0) {
@@ -897,9 +944,7 @@ static int __init usb_gigaset_init(void)
        info(DRIVER_DESC);
        return 0;
 
-error: if (cardstate)
-               gigaset_freecs(cardstate);
-       cardstate = NULL;
+error:
        if (driver)
                gigaset_freedriver(driver);
        driver = NULL;
@@ -913,11 +958,16 @@ error:    if (cardstate)
  */
 static void __exit usb_gigaset_exit(void)
 {
+       int i;
+
        gigaset_blockdriver(driver); /* => probe will fail
                                      * => no gigaset_start any more
                                      */
 
-       gigaset_shutdown(cardstate);
+       /* stop all connected devices */
+       for (i = 0; i < driver->minors; i++)
+               gigaset_shutdown(driver->cs + i);
+
        /* from now on, no isdn callback should be possible */
 
        /* deregister this driver with the USB subsystem */
@@ -925,8 +975,6 @@ static void __exit usb_gigaset_exit(void)
        /* this will call the disconnect-callback */
        /* from now on, no disconnect/probe callback should be running */
 
-       gigaset_freecs(cardstate);
-       cardstate = NULL;
        gigaset_freedriver(driver);
        driver = NULL;
 }
index 0db9cc6..84318ec 100644 (file)
@@ -1188,7 +1188,7 @@ int SuperTraceASSIGN (void* AdapterHandle, byte* data) {
 
     if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
         (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
-      dword rx_dma_magic;
+      dword uninitialized_var(rx_dma_magic);
       if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) {
         pC->xbuffer[0] = LLI;
         pC->xbuffer[1] = 8;
index ffa2afa..1403a54 100644 (file)
@@ -515,12 +515,11 @@ diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
 
 irqreturn_t diva_os_irq_wrapper(int irq, void *context)
 {
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
+       diva_os_xdi_adapter_t *a = context;
        diva_xdi_clear_interrupts_proc_t clear_int_proc;
 
-       if (!a || !a->xdi_adapter.diva_isr_handler) {
+       if (!a || !a->xdi_adapter.diva_isr_handler)
                return IRQ_NONE;
-       }
 
        if ((clear_int_proc = a->clear_interrupts_proc)) {
                (*clear_int_proc) (a);
index b9177ca..1ff98e7 100644 (file)
@@ -9027,7 +9027,7 @@ static byte AddInfo(byte   **add_i,
    /* facility is a nested structure */
    /* FTY can be more than once      */
 
-  if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f )
+       if (esc_chi[0] && !(esc_chi[esc_chi[0]] & 0x7f))
   {
     add_i[0] = (byte   *)"\x02\x02\x00"; /* use neither b nor d channel */
   }
index 035d158..0f1db1f 100644 (file)
@@ -263,11 +263,7 @@ hdlc_empty_fifo(struct BCState *bcs, int count)
                outl(idx, cs->hw.avm.cfg_reg + 4);
                while (cnt < count) {
 #ifdef __powerpc__
-#ifdef CONFIG_APUS
-                       *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#else
                        *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
-#endif /* CONFIG_APUS */
 #else
                        *ptr++ = inl(cs->hw.avm.isac);
 #endif /* __powerpc__ */
@@ -328,11 +324,7 @@ hdlc_fill_fifo(struct BCState *bcs)
        if (cs->subtyp == AVM_FRITZ_PCI) {
                while (cnt<count) {
 #ifdef __powerpc__
-#ifdef CONFIG_APUS
-                       out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#else
                        out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
-#endif /* CONFIG_APUS */
 #else
                        outl(*ptr++, cs->hw.avm.isac);
 #endif /* __powerpc__ */
index 9cb6e50..133eb18 100644 (file)
@@ -1917,7 +1917,6 @@ isdn_tty_modem_init(void)
                info->owner = THIS_MODULE;
 #endif
                spin_lock_init(&info->readlock);
-               init_MUTEX(&info->write_sem);
                sprintf(info->last_cause, "0000");
                sprintf(info->last_num, "none");
                info->last_dir = 0;
index a943d07..f93de4a 100644 (file)
@@ -834,7 +834,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
                char *rp = &f->resolution;
 
                p[0] += 2;
-               if (!info->faxonline & 1)       /* not outgoing connection */
+               if (!(info->faxonline & 1))     /* not outgoing connection */
                        PARSE_ERROR1;
 
                for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
index 82d957b..bf7997a 100644 (file)
@@ -1302,7 +1302,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_DIAL:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1328,7 +1328,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTD:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ICN_BCH) {
                                a = c->arg + 1;
@@ -1348,7 +1348,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTB:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ICN_BCH) {
                                a = c->arg + 1;
@@ -1366,7 +1366,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_HANGUP:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ICN_BCH) {
                                a = c->arg + 1;
@@ -1375,7 +1375,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_SETEAZ:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1391,7 +1391,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_CLREAZ:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1405,7 +1405,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_SETL2:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        if ((c->arg & 255) < ICN_BCH) {
                                a = c->arg;
@@ -1424,7 +1424,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                        }
                        break;
                case ISDN_CMD_SETL3:
-                       if (!card->flags & ICN_FLAGS_RUNNING)
+                       if (!(card->flags & ICN_FLAGS_RUNNING))
                                return -ENODEV;
                        return 0;
                default:
@@ -1471,7 +1471,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel)
        icn_card *card = icn_findcard(id);
 
        if (card) {
-               if (!card->flags & ICN_FLAGS_RUNNING)
+               if (!(card->flags & ICN_FLAGS_RUNNING))
                        return -ENODEV;
                return (icn_writecmd(buf, len, 1, card));
        }
@@ -1486,7 +1486,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel)
        icn_card *card = icn_findcard(id);
 
        if (card) {
-               if (!card->flags & ICN_FLAGS_RUNNING)
+               if (!(card->flags & ICN_FLAGS_RUNNING))
                        return -ENODEV;
                return (icn_readstatus(buf, len, card));
        }
@@ -1501,7 +1501,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
        icn_card *card = icn_findcard(id);
 
        if (card) {
-               if (!card->flags & ICN_FLAGS_RUNNING)
+               if (!(card->flags & ICN_FLAGS_RUNNING))
                        return -ENODEV;
                return (icn_sendbuf(channel, ack, skb, card));
        }
index bb92e3c..655ef9a 100644 (file)
@@ -1184,7 +1184,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                        }
                        break;
                case ISDN_CMD_DIAL:
-                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                return -ENODEV;
                        if (card->leased)
                                break;
@@ -1210,7 +1210,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTD:
-                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ISDNLOOP_BCH) {
                                a = c->arg + 1;
@@ -1238,7 +1238,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                        }
                        break;
                case ISDN_CMD_ACCEPTB:
-                       if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                return -ENODEV;
                        if (c->arg < ISDNLOOP_BCH) {
                                a = c->arg + 1;
@@ -1264,7 +1264,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                                i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
                                break;
                case ISDN_CMD_HANGUP:
-                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                        return -ENODEV;
                                if (c->arg < ISDNLOOP_BCH) {
                                        a = c->arg + 1;
@@ -1273,7 +1273,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                                }
                                break;
                case ISDN_CMD_SETEAZ:
-                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                        return -ENODEV;
                                if (card->leased)
                                        break;
@@ -1303,7 +1303,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                                }
                                break;
                case ISDN_CMD_SETL2:
-                               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                                        return -ENODEV;
                                if ((c->arg & 255) < ISDNLOOP_BCH) {
                                        a = c->arg;
@@ -1395,7 +1395,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel)
        isdnloop_card *card = isdnloop_findcard(id);
 
        if (card) {
-               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                        return -ENODEV;
                return (isdnloop_readstatus(buf, len, card));
        }
@@ -1410,7 +1410,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
        isdnloop_card *card = isdnloop_findcard(id);
 
        if (card) {
-               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+               if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
                        return -ENODEV;
                /* ack request stored in skb scratch area */
                *(skb->head) = ack;
index 1b1ef31..a0585fb 100644 (file)
@@ -237,7 +237,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
        if (!page)
                return ERR_PTR(-ENOMEM);
 
-       ITERATE_RDEV(mddev, rdev, tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (! test_bit(In_sync, &rdev->flags)
                    || test_bit(Faulty, &rdev->flags))
                        continue;
@@ -261,7 +261,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
        struct list_head *tmp;
        mddev_t *mddev = bitmap->mddev;
 
-       ITERATE_RDEV(mddev, rdev, tmp)
+       rdev_for_each(rdev, tmp, mddev)
                if (test_bit(In_sync, &rdev->flags)
                    && !test_bit(Faulty, &rdev->flags)) {
                        int size = PAGE_SIZE;
@@ -1348,14 +1348,38 @@ void bitmap_close_sync(struct bitmap *bitmap)
         */
        sector_t sector = 0;
        int blocks;
-       if (!bitmap) return;
+       if (!bitmap)
+               return;
        while (sector < bitmap->mddev->resync_max_sectors) {
                bitmap_end_sync(bitmap, sector, &blocks, 0);
-/*
-               if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n",
-                                        (unsigned long long)sector, blocks);
-*/             sector += blocks;
+               sector += blocks;
+       }
+}
+
+void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
+{
+       sector_t s = 0;
+       int blocks;
+
+       if (!bitmap)
+               return;
+       if (sector == 0) {
+               bitmap->last_end_sync = jiffies;
+               return;
+       }
+       if (time_before(jiffies, (bitmap->last_end_sync
+                                 + bitmap->daemon_sleep * HZ)))
+               return;
+       wait_event(bitmap->mddev->recovery_wait,
+                  atomic_read(&bitmap->mddev->recovery_active) == 0);
+
+       sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1);
+       s = 0;
+       while (s < sector && s < bitmap->mddev->resync_max_sectors) {
+               bitmap_end_sync(bitmap, s, &blocks, 0);
+               s += blocks;
        }
+       bitmap->last_end_sync = jiffies;
 }
 
 static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
@@ -1565,3 +1589,4 @@ EXPORT_SYMBOL(bitmap_start_sync);
 EXPORT_SYMBOL(bitmap_end_sync);
 EXPORT_SYMBOL(bitmap_unplug);
 EXPORT_SYMBOL(bitmap_close_sync);
+EXPORT_SYMBOL(bitmap_cond_end_sync);
index cf2ddce..d107ddc 100644 (file)
@@ -294,7 +294,7 @@ static int run(mddev_t *mddev)
        }
        conf->nfaults = 0;
 
-       ITERATE_RDEV(mddev, rdev, tmp)
+       rdev_for_each(rdev, tmp, mddev)
                conf->rdev = rdev;
 
        mddev->array_size = mddev->size;
index 3dac1cf..0b85117 100644 (file)
@@ -122,7 +122,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
        cnt = 0;
        conf->array_size = 0;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                int j = rdev->raid_disk;
                dev_info_t *disk = conf->disks + j;
 
index c28a120..5fc326d 100644 (file)
@@ -195,7 +195,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
  * Any code which breaks out of this loop while own
  * a reference to the current mddev and must mddev_put it.
  */
-#define ITERATE_MDDEV(mddev,tmp)                                       \
+#define for_each_mddev(mddev,tmp)                                      \
                                                                        \
        for (({ spin_lock(&all_mddevs_lock);                            \
                tmp = all_mddevs.next;                                  \
@@ -275,6 +275,7 @@ static mddev_t * mddev_find(dev_t unit)
        spin_lock_init(&new->write_lock);
        init_waitqueue_head(&new->sb_wait);
        new->reshape_position = MaxSector;
+       new->resync_max = MaxSector;
 
        new->queue = blk_alloc_queue(GFP_KERNEL);
        if (!new->queue) {
@@ -310,7 +311,7 @@ static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr)
        mdk_rdev_t * rdev;
        struct list_head *tmp;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev->desc_nr == nr)
                        return rdev;
        }
@@ -322,7 +323,7 @@ static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev)
        struct list_head *tmp;
        mdk_rdev_t *rdev;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev->bdev->bd_dev == dev)
                        return rdev;
        }
@@ -773,12 +774,16 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
        __u64 ev1 = md_event(sb);
 
        rdev->raid_disk = -1;
-       rdev->flags = 0;
+       clear_bit(Faulty, &rdev->flags);
+       clear_bit(In_sync, &rdev->flags);
+       clear_bit(WriteMostly, &rdev->flags);
+       clear_bit(BarriersNotsupp, &rdev->flags);
+
        if (mddev->raid_disks == 0) {
                mddev->major_version = 0;
                mddev->minor_version = sb->minor_version;
                mddev->patch_version = sb->patch_version;
-               mddev->persistent = ! sb->not_persistent;
+               mddev->external = 0;
                mddev->chunk_size = sb->chunk_size;
                mddev->ctime = sb->ctime;
                mddev->utime = sb->utime;
@@ -904,7 +909,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        sb->size  = mddev->size;
        sb->raid_disks = mddev->raid_disks;
        sb->md_minor = mddev->md_minor;
-       sb->not_persistent = !mddev->persistent;
+       sb->not_persistent = 0;
        sb->utime = mddev->utime;
        sb->state = 0;
        sb->events_hi = (mddev->events>>32);
@@ -938,7 +943,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
                sb->state |= (1<<MD_SB_BITMAP_PRESENT);
 
        sb->disks[0].state = (1<<MD_DISK_REMOVED);
-       ITERATE_RDEV(mddev,rdev2,tmp) {
+       rdev_for_each(rdev2, tmp, mddev) {
                mdp_disk_t *d;
                int desc_nr;
                if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
@@ -1153,11 +1158,15 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
        __u64 ev1 = le64_to_cpu(sb->events);
 
        rdev->raid_disk = -1;
-       rdev->flags = 0;
+       clear_bit(Faulty, &rdev->flags);
+       clear_bit(In_sync, &rdev->flags);
+       clear_bit(WriteMostly, &rdev->flags);
+       clear_bit(BarriersNotsupp, &rdev->flags);
+
        if (mddev->raid_disks == 0) {
                mddev->major_version = 1;
                mddev->patch_version = 0;
-               mddev->persistent = 1;
+               mddev->external = 0;
                mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9;
                mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
                mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
@@ -1286,7 +1295,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        }
 
        max_dev = 0;
-       ITERATE_RDEV(mddev,rdev2,tmp)
+       rdev_for_each(rdev2, tmp, mddev)
                if (rdev2->desc_nr+1 > max_dev)
                        max_dev = rdev2->desc_nr+1;
 
@@ -1295,7 +1304,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        for (i=0; i<max_dev;i++)
                sb->dev_roles[i] = cpu_to_le16(0xfffe);
        
-       ITERATE_RDEV(mddev,rdev2,tmp) {
+       rdev_for_each(rdev2, tmp, mddev) {
                i = rdev2->desc_nr;
                if (test_bit(Faulty, &rdev2->flags))
                        sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1333,8 +1342,8 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
        struct list_head *tmp, *tmp2;
        mdk_rdev_t *rdev, *rdev2;
 
-       ITERATE_RDEV(mddev1,rdev,tmp)
-               ITERATE_RDEV(mddev2, rdev2, tmp2)
+       rdev_for_each(rdev, tmp, mddev1)
+               rdev_for_each(rdev2, tmp2, mddev2)
                        if (rdev->bdev->bd_contains ==
                            rdev2->bdev->bd_contains)
                                return 1;
@@ -1401,7 +1410,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
                goto fail;
        }
        list_add(&rdev->same_set, &mddev->disks);
-       bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk);
+       bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
        return 0;
 
  fail:
@@ -1410,10 +1419,11 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
        return err;
 }
 
-static void delayed_delete(struct work_struct *ws)
+static void md_delayed_delete(struct work_struct *ws)
 {
        mdk_rdev_t *rdev = container_of(ws, mdk_rdev_t, del_work);
        kobject_del(&rdev->kobj);
+       kobject_put(&rdev->kobj);
 }
 
 static void unbind_rdev_from_array(mdk_rdev_t * rdev)
@@ -1432,7 +1442,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
        /* We need to delay this, otherwise we can deadlock when
         * writing to 'remove' to "dev/state"
         */
-       INIT_WORK(&rdev->del_work, delayed_delete);
+       INIT_WORK(&rdev->del_work, md_delayed_delete);
+       kobject_get(&rdev->kobj);
        schedule_work(&rdev->del_work);
 }
 
@@ -1441,7 +1452,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
  * otherwise reused by a RAID array (or any other kernel
  * subsystem), by bd_claiming the device.
  */
-static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
+static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
 {
        int err = 0;
        struct block_device *bdev;
@@ -1453,13 +1464,15 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
                        __bdevname(dev, b));
                return PTR_ERR(bdev);
        }
-       err = bd_claim(bdev, rdev);
+       err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev);
        if (err) {
                printk(KERN_ERR "md: could not bd_claim %s.\n",
                        bdevname(bdev, b));
                blkdev_put(bdev);
                return err;
        }
+       if (!shared)
+               set_bit(AllReserved, &rdev->flags);
        rdev->bdev = bdev;
        return err;
 }
@@ -1503,7 +1516,7 @@ static void export_array(mddev_t *mddev)
        struct list_head *tmp;
        mdk_rdev_t *rdev;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (!rdev->mddev) {
                        MD_BUG();
                        continue;
@@ -1581,17 +1594,17 @@ static void md_print_devices(void)
        printk("md:     **********************************\n");
        printk("md:     * <COMPLETE RAID STATE PRINTOUT> *\n");
        printk("md:     **********************************\n");
-       ITERATE_MDDEV(mddev,tmp) {
+       for_each_mddev(mddev, tmp) {
 
                if (mddev->bitmap)
                        bitmap_print_sb(mddev->bitmap);
                else
                        printk("%s: ", mdname(mddev));
-               ITERATE_RDEV(mddev,rdev,tmp2)
+               rdev_for_each(rdev, tmp2, mddev)
                        printk("<%s>", bdevname(rdev->bdev,b));
                printk("\n");
 
-               ITERATE_RDEV(mddev,rdev,tmp2)
+               rdev_for_each(rdev, tmp2, mddev)
                        print_rdev(rdev);
        }
        printk("md:     **********************************\n");
@@ -1610,7 +1623,7 @@ static void sync_sbs(mddev_t * mddev, int nospares)
        mdk_rdev_t *rdev;
        struct list_head *tmp;
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev->sb_events == mddev->events ||
                    (nospares &&
                     rdev->raid_disk < 0 &&
@@ -1696,18 +1709,20 @@ repeat:
                MD_BUG();
                mddev->events --;
        }
-       sync_sbs(mddev, nospares);
 
        /*
         * do not write anything to disk if using
         * nonpersistent superblocks
         */
        if (!mddev->persistent) {
-               clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+               if (!mddev->external)
+                       clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+
                spin_unlock_irq(&mddev->write_lock);
                wake_up(&mddev->sb_wait);
                return;
        }
+       sync_sbs(mddev, nospares);
        spin_unlock_irq(&mddev->write_lock);
 
        dprintk(KERN_INFO 
@@ -1715,7 +1730,7 @@ repeat:
                mdname(mddev),mddev->in_sync);
 
        bitmap_update_sb(mddev->bitmap);
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                char b[BDEVNAME_SIZE];
                dprintk(KERN_INFO "md: ");
                if (rdev->sb_loaded != 1)
@@ -1785,7 +1800,7 @@ static ssize_t
 state_show(mdk_rdev_t *rdev, char *page)
 {
        char *sep = "";
-       int len=0;
+       size_t len = 0;
 
        if (test_bit(Faulty, &rdev->flags)) {
                len+= sprintf(page+len, "%sfaulty",sep);
@@ -1887,20 +1902,45 @@ static ssize_t
 slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 {
        char *e;
+       int err;
+       char nm[20];
        int slot = simple_strtoul(buf, &e, 10);
        if (strncmp(buf, "none", 4)==0)
                slot = -1;
        else if (e==buf || (*e && *e!= '\n'))
                return -EINVAL;
-       if (rdev->mddev->pers)
-               /* Cannot set slot in active array (yet) */
-               return -EBUSY;
-       if (slot >= rdev->mddev->raid_disks)
-               return -ENOSPC;
-       rdev->raid_disk = slot;
-       /* assume it is working */
-       rdev->flags = 0;
-       set_bit(In_sync, &rdev->flags);
+       if (rdev->mddev->pers) {
+               /* Setting 'slot' on an active array requires also
+                * updating the 'rd%d' link, and communicating
+                * with the personality with ->hot_*_disk.
+                * For now we only support removing
+                * failed/spare devices.  This normally happens automatically,
+                * but not when the metadata is externally managed.
+                */
+               if (slot != -1)
+                       return -EBUSY;
+               if (rdev->raid_disk == -1)
+                       return -EEXIST;
+               /* personality does all needed checks */
+               if (rdev->mddev->pers->hot_add_disk == NULL)
+                       return -EINVAL;
+               err = rdev->mddev->pers->
+                       hot_remove_disk(rdev->mddev, rdev->raid_disk);
+               if (err)
+                       return err;
+               sprintf(nm, "rd%d", rdev->raid_disk);
+               sysfs_remove_link(&rdev->mddev->kobj, nm);
+               set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
+               md_wakeup_thread(rdev->mddev->thread);
+       } else {
+               if (slot >= rdev->mddev->raid_disks)
+                       return -ENOSPC;
+               rdev->raid_disk = slot;
+               /* assume it is working */
+               clear_bit(Faulty, &rdev->flags);
+               clear_bit(WriteMostly, &rdev->flags);
+               set_bit(In_sync, &rdev->flags);
+       }
        return len;
 }
 
@@ -1923,6 +1963,10 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                return -EINVAL;
        if (rdev->mddev->pers)
                return -EBUSY;
+       if (rdev->size && rdev->mddev->external)
+               /* Must set offset before size, so overlap checks
+                * can be sane */
+               return -EBUSY;
        rdev->data_offset = offset;
        return len;
 }
@@ -1936,16 +1980,69 @@ rdev_size_show(mdk_rdev_t *rdev, char *page)
        return sprintf(page, "%llu\n", (unsigned long long)rdev->size);
 }
 
+static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
+{
+       /* check if two start/length pairs overlap */
+       if (s1+l1 <= s2)
+               return 0;
+       if (s2+l2 <= s1)
+               return 0;
+       return 1;
+}
+
 static ssize_t
 rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 {
        char *e;
        unsigned long long size = simple_strtoull(buf, &e, 10);
+       unsigned long long oldsize = rdev->size;
        if (e==buf || (*e && *e != '\n'))
                return -EINVAL;
        if (rdev->mddev->pers)
                return -EBUSY;
        rdev->size = size;
+       if (size > oldsize && rdev->mddev->external) {
+               /* need to check that all other rdevs with the same ->bdev
+                * do not overlap.  We need to unlock the mddev to avoid
+                * a deadlock.  We have already changed rdev->size, and if
+                * we have to change it back, we will have the lock again.
+                */
+               mddev_t *mddev;
+               int overlap = 0;
+               struct list_head *tmp, *tmp2;
+
+               mddev_unlock(rdev->mddev);
+               for_each_mddev(mddev, tmp) {
+                       mdk_rdev_t *rdev2;
+
+                       mddev_lock(mddev);
+                       rdev_for_each(rdev2, tmp2, mddev)
+                               if (test_bit(AllReserved, &rdev2->flags) ||
+                                   (rdev->bdev == rdev2->bdev &&
+                                    rdev != rdev2 &&
+                                    overlaps(rdev->data_offset, rdev->size,
+                                           rdev2->data_offset, rdev2->size))) {
+                                       overlap = 1;
+                                       break;
+                               }
+                       mddev_unlock(mddev);
+                       if (overlap) {
+                               mddev_put(mddev);
+                               break;
+                       }
+               }
+               mddev_lock(rdev->mddev);
+               if (overlap) {
+                       /* Someone else could have slipped in a size
+                        * change here, but doing so is just silly.
+                        * We put oldsize back because we *know* it is
+                        * safe, and trust userspace not to race with
+                        * itself
+                        */
+                       rdev->size = oldsize;
+                       return -EBUSY;
+               }
+       }
        if (size < rdev->mddev->size || rdev->mddev->size == 0)
                rdev->mddev->size = size;
        return len;
@@ -1980,12 +2077,18 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
 {
        struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
        mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+       int rv;
 
        if (!entry->store)
                return -EIO;
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
-       return entry->store(rdev, page, length);
+       rv = mddev_lock(rdev->mddev);
+       if (!rv) {
+               rv = entry->store(rdev, page, length);
+               mddev_unlock(rdev->mddev);
+       }
+       return rv;
 }
 
 static void rdev_free(struct kobject *ko)
@@ -2029,7 +2132,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
        if ((err = alloc_disk_sb(rdev)))
                goto abort_free;
 
-       err = lock_rdev(rdev, newdev);
+       err = lock_rdev(rdev, newdev, super_format == -2);
        if (err)
                goto abort_free;
 
@@ -2099,7 +2202,7 @@ static void analyze_sbs(mddev_t * mddev)
        char b[BDEVNAME_SIZE];
 
        freshest = NULL;
-       ITERATE_RDEV(mddev,rdev,tmp)
+       rdev_for_each(rdev, tmp, mddev)
                switch (super_types[mddev->major_version].
                        load_super(rdev, freshest, mddev->minor_version)) {
                case 1:
@@ -2120,7 +2223,7 @@ static void analyze_sbs(mddev_t * mddev)
                validate_super(mddev, freshest);
 
        i = 0;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (rdev != freshest)
                        if (super_types[mddev->major_version].
                            validate_super(mddev, rdev)) {
@@ -2215,7 +2318,7 @@ level_show(mddev_t *mddev, char *page)
 static ssize_t
 level_store(mddev_t *mddev, const char *buf, size_t len)
 {
-       int rv = len;
+       ssize_t rv = len;
        if (mddev->pers)
                return -EBUSY;
        if (len == 0)
@@ -2425,6 +2528,8 @@ array_state_show(mddev_t *mddev, char *page)
                case 0:
                        if (mddev->in_sync)
                                st = clean;
+                       else if (test_bit(MD_CHANGE_CLEAN, &mddev->flags))
+                               st = write_pending;
                        else if (mddev->safemode)
                                st = active_idle;
                        else
@@ -2455,11 +2560,9 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
                break;
        case clear:
                /* stopping an active array */
-               if (mddev->pers) {
-                       if (atomic_read(&mddev->active) > 1)
-                               return -EBUSY;
-                       err = do_md_stop(mddev, 0);
-               }
+               if (atomic_read(&mddev->active) > 1)
+                       return -EBUSY;
+               err = do_md_stop(mddev, 0);
                break;
        case inactive:
                /* stopping an active array */
@@ -2467,7 +2570,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
                        if (atomic_read(&mddev->active) > 1)
                                return -EBUSY;
                        err = do_md_stop(mddev, 2);
-               }
+               } else
+                       err = 0; /* already inactive */
                break;
        case suspended:
                break; /* not supported yet */
@@ -2495,9 +2599,15 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
                        restart_array(mddev);
                        spin_lock_irq(&mddev->write_lock);
                        if (atomic_read(&mddev->writes_pending) == 0) {
-                               mddev->in_sync = 1;
-                               set_bit(MD_CHANGE_CLEAN, &mddev->flags);
-                       }
+                               if (mddev->in_sync == 0) {
+                                       mddev->in_sync = 1;
+                                       if (mddev->persistent)
+                                               set_bit(MD_CHANGE_CLEAN,
+                                                       &mddev->flags);
+                               }
+                               err = 0;
+                       } else
+                               err = -EBUSY;
                        spin_unlock_irq(&mddev->write_lock);
                } else {
                        mddev->ro = 0;
@@ -2508,7 +2618,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
        case active:
                if (mddev->pers) {
                        restart_array(mddev);
-                       clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
+                       if (mddev->external)
+                               clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
                        wake_up(&mddev->sb_wait);
                        err = 0;
                } else {
@@ -2574,7 +2685,9 @@ new_dev_store(mddev_t *mddev, const char *buf, size_t len)
                        if (err < 0)
                                goto out;
                }
-       } else
+       } else if (mddev->external)
+               rdev = md_import_device(dev, -2, -1);
+       else
                rdev = md_import_device(dev, -1, -1);
 
        if (IS_ERR(rdev))
@@ -2659,7 +2772,9 @@ __ATTR(component_size, S_IRUGO|S_IWUSR, size_show, size_store);
 
 
 /* Metdata version.
- * This is either 'none' for arrays with externally managed metadata,
+ * This is one of
+ *   'none' for arrays with no metadata (good luck...)
+ *   'external' for arrays with externally managed metadata,
  * or N.M for internally known formats
  */
 static ssize_t
@@ -2668,6 +2783,8 @@ metadata_show(mddev_t *mddev, char *page)
        if (mddev->persistent)
                return sprintf(page, "%d.%d\n",
                               mddev->major_version, mddev->minor_version);
+       else if (mddev->external)
+               return sprintf(page, "external:%s\n", mddev->metadata_type);
        else
                return sprintf(page, "none\n");
 }
@@ -2682,6 +2799,21 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
 
        if (cmd_match(buf, "none")) {
                mddev->persistent = 0;
+               mddev->external = 0;
+               mddev->major_version = 0;
+               mddev->minor_version = 90;
+               return len;
+       }
+       if (strncmp(buf, "external:", 9) == 0) {
+               size_t namelen = len-9;
+               if (namelen >= sizeof(mddev->metadata_type))
+                       namelen = sizeof(mddev->metadata_type)-1;
+               strncpy(mddev->metadata_type, buf+9, namelen);
+               mddev->metadata_type[namelen] = 0;
+               if (namelen && mddev->metadata_type[namelen-1] == '\n')
+                       mddev->metadata_type[--namelen] = 0;
+               mddev->persistent = 0;
+               mddev->external = 1;
                mddev->major_version = 0;
                mddev->minor_version = 90;
                return len;
@@ -2698,6 +2830,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
        mddev->major_version = major;
        mddev->minor_version = minor;
        mddev->persistent = 1;
+       mddev->external = 0;
        return len;
 }
 
@@ -2864,6 +2997,43 @@ sync_completed_show(mddev_t *mddev, char *page)
 
 static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
 
+static ssize_t
+max_sync_show(mddev_t *mddev, char *page)
+{
+       if (mddev->resync_max == MaxSector)
+               return sprintf(page, "max\n");
+       else
+               return sprintf(page, "%llu\n",
+                              (unsigned long long)mddev->resync_max);
+}
+static ssize_t
+max_sync_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       if (strncmp(buf, "max", 3) == 0)
+               mddev->resync_max = MaxSector;
+       else {
+               char *ep;
+               unsigned long long max = simple_strtoull(buf, &ep, 10);
+               if (ep == buf || (*ep != 0 && *ep != '\n'))
+                       return -EINVAL;
+               if (max < mddev->resync_max &&
+                   test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+                       return -EBUSY;
+
+               /* Must be a multiple of chunk_size */
+               if (mddev->chunk_size) {
+                       if (max & (sector_t)((mddev->chunk_size>>9)-1))
+                               return -EINVAL;
+               }
+               mddev->resync_max = max;
+       }
+       wake_up(&mddev->recovery_wait);
+       return len;
+}
+
+static struct md_sysfs_entry md_max_sync =
+__ATTR(sync_max, S_IRUGO|S_IWUSR, max_sync_show, max_sync_store);
+
 static ssize_t
 suspend_lo_show(mddev_t *mddev, char *page)
 {
@@ -2974,6 +3144,7 @@ static struct attribute *md_redundancy_attrs[] = {
        &md_sync_max.attr,
        &md_sync_speed.attr,
        &md_sync_completed.attr,
+       &md_max_sync.attr,
        &md_suspend_lo.attr,
        &md_suspend_hi.attr,
        &md_bitmap.attr,
@@ -3118,8 +3289,11 @@ static int do_md_run(mddev_t * mddev)
        /*
         * Analyze all RAID superblock(s)
         */
-       if (!mddev->raid_disks)
+       if (!mddev->raid_disks) {
+               if (!mddev->persistent)
+                       return -EINVAL;
                analyze_sbs(mddev);
+       }
 
        chunk_size = mddev->chunk_size;
 
@@ -3143,7 +3317,7 @@ static int do_md_run(mddev_t * mddev)
                }
 
                /* devices must have minimum size of one chunk */
-               ITERATE_RDEV(mddev,rdev,tmp) {
+               rdev_for_each(rdev, tmp, mddev) {
                        if (test_bit(Faulty, &rdev->flags))
                                continue;
                        if (rdev->size < chunk_size / 1024) {
@@ -3170,7 +3344,7 @@ static int do_md_run(mddev_t * mddev)
         * the only valid external interface is through the md
         * device.
         */
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                if (test_bit(Faulty, &rdev->flags))
                        continue;
                sync_blockdev(rdev->bdev);
@@ -3236,8 +3410,8 @@ static int do_md_run(mddev_t * mddev)
                mdk_rdev_t *rdev2;
                struct list_head *tmp2;
                int warned = 0;
-               ITERATE_RDEV(mddev, rdev, tmp) {
-                       ITERATE_RDEV(mddev, rdev2, tmp2) {
+               rdev_for_each(rdev, tmp, mddev) {
+                       rdev_for_each(rdev2, tmp2, mddev) {
                                if (rdev < rdev2 &&
                                    rdev->bdev->bd_contains ==
                                    rdev2->bdev->bd_contains) {
@@ -3297,7 +3471,7 @@ static int do_md_run(mddev_t * mddev)
        mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
        mddev->in_sync = 1;
 
-       ITERATE_RDEV(mddev,rdev,tmp)
+       rdev_for_each(rdev, tmp, mddev)
                if (rdev->raid_disk >= 0) {
                        char nm[20];
                        sprintf(nm, "rd%d", rdev->raid_disk);
@@ -3330,7 +3504,7 @@ static int do_md_run(mddev_t * mddev)
        if (mddev->degraded && !mddev->sync_thread) {
                struct list_head *rtmp;
                int spares = 0;
-               ITERATE_RDEV(mddev,rdev,rtmp)
+               rdev_for_each(rdev, rtmp, mddev)
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(In_sync, &rdev->flags) &&
                            !test_bit(Faulty, &rdev->flags))
@@ -3507,14 +3681,14 @@ static int do_md_stop(mddev_t * mddev, int mode)
                }
                mddev->bitmap_offset = 0;
 
-               ITERATE_RDEV(mddev,rdev,tmp)
+               rdev_for_each(rdev, tmp, mddev)
                        if (rdev->raid_disk >= 0) {
                                char nm[20];
                                sprintf(nm, "rd%d", rdev->raid_disk);
                                sysfs_remove_link(&mddev->kobj, nm);
                        }
 
-               /* make sure all delayed_delete calls have finished */
+               /* make sure all md_delayed_delete calls have finished */
                flush_scheduled_work();
 
                export_array(mddev);
@@ -3523,7 +3697,10 @@ static int do_md_stop(mddev_t * mddev, int mode)
                mddev->size = 0;
                mddev->raid_disks = 0;
                mddev->recovery_cp = 0;
+               mddev->resync_max = MaxSector;
                mddev->reshape_position = MaxSector;
+               mddev->external = 0;
+               mddev->persistent = 0;
 
        } else if (mddev->pers)
                printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -3546,7 +3723,7 @@ static void autorun_array(mddev_t *mddev)
 
        printk(KERN_INFO "md: running: ");
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                char b[BDEVNAME_SIZE];
                printk("<%s>", bdevname(rdev->bdev,b));
        }
@@ -3589,7 +3766,7 @@ static void autorun_devices(int part)
                printk(KERN_INFO "md: considering %s ...\n",
                        bdevname(rdev0->bdev,b));
                INIT_LIST_HEAD(&candidates);
-               ITERATE_RDEV_PENDING(rdev,tmp)
+               rdev_for_each_list(rdev, tmp, pending_raid_disks)
                        if (super_90_load(rdev, rdev0, 0) >= 0) {
                                printk(KERN_INFO "md:  adding %s ...\n",
                                        bdevname(rdev->bdev,b));
@@ -3632,7 +3809,8 @@ static void autorun_devices(int part)
                        mddev_unlock(mddev);
                } else {
                        printk(KERN_INFO "md: created %s\n", mdname(mddev));
-                       ITERATE_RDEV_GENERIC(candidates,rdev,tmp) {
+                       mddev->persistent = 1;
+                       rdev_for_each_list(rdev, tmp, candidates) {
                                list_del_init(&rdev->same_set);
                                if (bind_rdev_to_array(rdev, mddev))
                                        export_rdev(rdev);
@@ -3643,7 +3821,7 @@ static void autorun_devices(int part)
                /* on success, candidates will be empty, on error
                 * it won't...
                 */
-               ITERATE_RDEV_GENERIC(candidates,rdev,tmp)
+               rdev_for_each_list(rdev, tmp, candidates)
                        export_rdev(rdev);
                mddev_put(mddev);
        }
@@ -3673,7 +3851,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
        struct list_head *tmp;
 
        nr=working=active=failed=spare=0;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                nr++;
                if (test_bit(Faulty, &rdev->flags))
                        failed++;
@@ -3919,8 +4097,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                else
                        rdev->raid_disk = -1;
 
-               rdev->flags = 0;
-
                if (rdev->raid_disk < mddev->raid_disks)
                        if (info->state & (1<<MD_DISK_SYNC))
                                set_bit(In_sync, &rdev->flags);
@@ -4165,13 +4341,15 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
        else
                mddev->recovery_cp = 0;
        mddev->persistent    = ! info->not_persistent;
+       mddev->external      = 0;
 
        mddev->layout        = info->layout;
        mddev->chunk_size    = info->chunk_size;
 
        mddev->max_disks     = MD_SB_DISKS;
 
-       mddev->flags         = 0;
+       if (mddev->persistent)
+               mddev->flags         = 0;
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
 
        mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
@@ -4213,7 +4391,7 @@ static int update_size(mddev_t *mddev, unsigned long size)
         */
        if (mddev->sync_thread)
                return -EBUSY;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                sector_t avail;
                avail = rdev->size * 2;
 
@@ -4471,9 +4649,10 @@ static int md_ioctl(struct inode *inode, struct file *file,
         */
        /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
         * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
-       if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
-                       && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
-                       && cmd != GET_BITMAP_FILE) {
+       if ((!mddev->raid_disks && !mddev->external)
+           && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
+           && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
+           && cmd != GET_BITMAP_FILE) {
                err = -ENODEV;
                goto abort_unlock;
        }
@@ -4757,7 +4936,7 @@ static void status_unused(struct seq_file *seq)
 
        seq_printf(seq, "unused devices: ");
 
-       ITERATE_RDEV_PENDING(rdev,tmp) {
+       rdev_for_each_list(rdev, tmp, pending_raid_disks) {
                char b[BDEVNAME_SIZE];
                i++;
                seq_printf(seq, "%s ",
@@ -4953,7 +5132,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
                }
 
                size = 0;
-               ITERATE_RDEV(mddev,rdev,tmp2) {
+               rdev_for_each(rdev, tmp2, mddev) {
                        char b[BDEVNAME_SIZE];
                        seq_printf(seq, " %s[%d]",
                                bdevname(rdev->bdev,b), rdev->desc_nr);
@@ -4982,7 +5161,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
                                           mddev->major_version,
                                           mddev->minor_version);
                        }
-               } else
+               } else if (mddev->external)
+                       seq_printf(seq, " super external:%s",
+                                  mddev->metadata_type);
+               else
                        seq_printf(seq, " super non-persistent");
 
                if (mddev->pers) {
@@ -5106,7 +5288,7 @@ static int is_mddev_idle(mddev_t *mddev)
        long curr_events;
 
        idle = 1;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
                curr_events = disk_stat_read(disk, sectors[0]) + 
                                disk_stat_read(disk, sectors[1]) - 
@@ -5283,7 +5465,7 @@ void md_do_sync(mddev_t *mddev)
                        set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                        goto skip;
                }
-               ITERATE_MDDEV(mddev2,tmp) {
+               for_each_mddev(mddev2, tmp) {
                        if (mddev2 == mddev)
                                continue;
                        if (mddev2->curr_resync && 
@@ -5333,7 +5515,7 @@ void md_do_sync(mddev_t *mddev)
                /* recovery follows the physical size of devices */
                max_sectors = mddev->size << 1;
                j = MaxSector;
-               ITERATE_RDEV(mddev,rdev,rtmp)
+               rdev_for_each(rdev, rtmp, mddev)
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(Faulty, &rdev->flags) &&
                            !test_bit(In_sync, &rdev->flags) &&
@@ -5381,8 +5563,16 @@ void md_do_sync(mddev_t *mddev)
                sector_t sectors;
 
                skipped = 0;
+               if (j >= mddev->resync_max) {
+                       sysfs_notify(&mddev->kobj, NULL, "sync_completed");
+                       wait_event(mddev->recovery_wait,
+                                  mddev->resync_max > j
+                                  || kthread_should_stop());
+               }
+               if (kthread_should_stop())
+                       goto interrupted;
                sectors = mddev->pers->sync_request(mddev, j, &skipped,
-                                           currspeed < speed_min(mddev));
+                                                 currspeed < speed_min(mddev));
                if (sectors == 0) {
                        set_bit(MD_RECOVERY_ERR, &mddev->recovery);
                        goto out;
@@ -5424,15 +5614,9 @@ void md_do_sync(mddev_t *mddev)
                }
 
 
-               if (kthread_should_stop()) {
-                       /*
-                        * got a signal, exit.
-                        */
-                       printk(KERN_INFO 
-                               "md: md_do_sync() got signal ... exiting\n");
-                       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
-                       goto out;
-               }
+               if (kthread_should_stop())
+                       goto interrupted;
+
 
                /*
                 * this loop exits only if either when we are slower than
@@ -5484,7 +5668,7 @@ void md_do_sync(mddev_t *mddev)
                } else {
                        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
                                mddev->curr_resync = MaxSector;
-                       ITERATE_RDEV(mddev,rdev,rtmp)
+                       rdev_for_each(rdev, rtmp, mddev)
                                if (rdev->raid_disk >= 0 &&
                                    !test_bit(Faulty, &rdev->flags) &&
                                    !test_bit(In_sync, &rdev->flags) &&
@@ -5496,9 +5680,22 @@ void md_do_sync(mddev_t *mddev)
 
  skip:
        mddev->curr_resync = 0;
+       mddev->resync_max = MaxSector;
+       sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        wake_up(&resync_wait);
        set_bit(MD_RECOVERY_DONE, &mddev->recovery);
        md_wakeup_thread(mddev->thread);
+       return;
+
+ interrupted:
+       /*
+        * got a signal, exit.
+        */
+       printk(KERN_INFO
+              "md: md_do_sync() got signal ... exiting\n");
+       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+       goto out;
+
 }
 EXPORT_SYMBOL_GPL(md_do_sync);
 
@@ -5509,8 +5706,9 @@ static int remove_and_add_spares(mddev_t *mddev)
        struct list_head *rtmp;
        int spares = 0;
 
-       ITERATE_RDEV(mddev,rdev,rtmp)
+       rdev_for_each(rdev, rtmp, mddev)
                if (rdev->raid_disk >= 0 &&
+                   !mddev->external &&
                    (test_bit(Faulty, &rdev->flags) ||
                     ! test_bit(In_sync, &rdev->flags)) &&
                    atomic_read(&rdev->nr_pending)==0) {
@@ -5524,7 +5722,7 @@ static int remove_and_add_spares(mddev_t *mddev)
                }
 
        if (mddev->degraded) {
-               ITERATE_RDEV(mddev,rdev,rtmp)
+               rdev_for_each(rdev, rtmp, mddev)
                        if (rdev->raid_disk < 0
                            && !test_bit(Faulty, &rdev->flags)) {
                                rdev->recovery_offset = 0;
@@ -5589,7 +5787,7 @@ void md_check_recovery(mddev_t *mddev)
        }
 
        if ( ! (
-               mddev->flags ||
+               (mddev->flags && !mddev->external) ||
                test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
                test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
                (mddev->safemode == 1) ||
@@ -5605,7 +5803,8 @@ void md_check_recovery(mddev_t *mddev)
                if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
                    !mddev->in_sync && mddev->recovery_cp == MaxSector) {
                        mddev->in_sync = 1;
-                       set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+                       if (mddev->persistent)
+                               set_bit(MD_CHANGE_CLEAN, &mddev->flags);
                }
                if (mddev->safemode == 1)
                        mddev->safemode = 0;
@@ -5637,7 +5836,7 @@ void md_check_recovery(mddev_t *mddev)
                         * information must be scrapped
                         */
                        if (!mddev->degraded)
-                               ITERATE_RDEV(mddev,rdev,rtmp)
+                               rdev_for_each(rdev, rtmp, mddev)
                                        rdev->saved_raid_disk = -1;
 
                        mddev->recovery = 0;
@@ -5714,7 +5913,7 @@ static int md_notify_reboot(struct notifier_block *this,
 
                printk(KERN_INFO "md: stopping all md devices.\n");
 
-               ITERATE_MDDEV(mddev,tmp)
+               for_each_mddev(mddev, tmp)
                        if (mddev_trylock(mddev)) {
                                do_md_stop (mddev, 1);
                                mddev_unlock(mddev);
@@ -5848,7 +6047,7 @@ static __exit void md_exit(void)
        unregister_reboot_notifier(&md_notifier);
        unregister_sysctl_table(raid_table_header);
        remove_proc_entry("mdstat", NULL);
-       ITERATE_MDDEV(mddev,tmp) {
+       for_each_mddev(mddev, tmp) {
                struct gendisk *disk = mddev->gendisk;
                if (!disk)
                        continue;
index adef299..b61d576 100644 (file)
@@ -1,13 +1,10 @@
-#ident "$Id: mktables.c,v 1.2 2002/12/12 22:41:27 hpa Exp $"
-/* ----------------------------------------------------------------------- *
+/* -*- linux-c -*- ------------------------------------------------------- *
  *
- *   Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2002-2007 H. Peter Anvin - 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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
- *   (at your option) any later version; incorporated herein by reference.
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2 or (at your
+ *   option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
 
 
 static uint8_t gfmul(uint8_t a, uint8_t b)
 {
-  uint8_t v = 0;
-
-  while ( b ) {
-    if ( b & 1 ) v ^= a;
-    a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
-    b >>= 1;
-  }
-  return v;
+       uint8_t v = 0;
+
+       while (b) {
+               if (b & 1)
+                       v ^= a;
+               a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
+               b >>= 1;
+       }
+
+       return v;
 }
 
 static uint8_t gfpow(uint8_t a, int b)
 {
-  uint8_t v = 1;
-
-  b %= 255;
-  if ( b < 0 )
-    b += 255;
-
-  while ( b ) {
-    if ( b & 1 ) v = gfmul(v,a);
-    a = gfmul(a,a);
-    b >>= 1;
-  }
-  return v;
+       uint8_t v = 1;
+
+       b %= 255;
+       if (b < 0)
+               b += 255;
+
+       while (b) {
+               if (b & 1)
+                       v = gfmul(v, a);
+               a = gfmul(a, a);
+               b >>= 1;
+       }
+
+       return v;
 }
 
 int main(int argc, char *argv[])
 {
-  int i, j, k;
-  uint8_t v;
-  uint8_t exptbl[256], invtbl[256];
-
-  printf("#include \"raid6.h\"\n");
-
-  /* Compute multiplication table */
-  printf("\nconst u8  __attribute__((aligned(256)))\n"
-        "raid6_gfmul[256][256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i++ ) {
-    printf("\t{\n");
-    for ( j = 0 ; j < 256 ; j += 8 ) {
-      printf("\t\t");
-      for ( k = 0 ; k < 8 ; k++ ) {
-       printf("0x%02x, ", gfmul(i,j+k));
-      }
-      printf("\n");
-    }
-    printf("\t},\n");
-  }
-  printf("};\n");
-
-  /* Compute power-of-2 table (exponent) */
-  v = 1;
-  printf("\nconst u8 __attribute__((aligned(256)))\n"
-        "raid6_gfexp[256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i += 8 ) {
-    printf("\t");
-    for ( j = 0 ; j < 8 ; j++ ) {
-      exptbl[i+j] = v;
-      printf("0x%02x, ", v);
-      v = gfmul(v,2);
-      if ( v == 1 ) v = 0;     /* For entry 255, not a real entry */
-    }
-    printf("\n");
-  }
-  printf("};\n");
-
-  /* Compute inverse table x^-1 == x^254 */
-  printf("\nconst u8 __attribute__((aligned(256)))\n"
-        "raid6_gfinv[256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i += 8 ) {
-    printf("\t");
-    for ( j = 0 ; j < 8 ; j++ ) {
-      invtbl[i+j] = v = gfpow(i+j,254);
-      printf("0x%02x, ", v);
-    }
-    printf("\n");
-  }
-  printf("};\n");
-
-  /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
-  printf("\nconst u8 __attribute__((aligned(256)))\n"
-        "raid6_gfexi[256] =\n"
-        "{\n");
-  for ( i = 0 ; i < 256 ; i += 8 ) {
-    printf("\t");
-    for ( j = 0 ; j < 8 ; j++ ) {
-      printf("0x%02x, ", invtbl[exptbl[i+j]^1]);
-    }
-    printf("\n");
-  }
-  printf("};\n\n");
-
-  return 0;
+       int i, j, k;
+       uint8_t v;
+       uint8_t exptbl[256], invtbl[256];
+
+       printf("#include \"raid6.h\"\n");
+
+       /* Compute multiplication table */
+       printf("\nconst u8  __attribute__((aligned(256)))\n"
+               "raid6_gfmul[256][256] =\n"
+               "{\n");
+       for (i = 0; i < 256; i++) {
+               printf("\t{\n");
+               for (j = 0; j < 256; j += 8) {
+                       printf("\t\t");
+                       for (k = 0; k < 8; k++)
+                               printf("0x%02x,%c", gfmul(i, j + k),
+                                      (k == 7) ? '\n' : ' ');
+               }
+               printf("\t},\n");
+       }
+       printf("};\n");
+
+       /* Compute power-of-2 table (exponent) */
+       v = 1;
+       printf("\nconst u8 __attribute__((aligned(256)))\n"
+              "raid6_gfexp[256] =\n" "{\n");
+       for (i = 0; i < 256; i += 8) {
+               printf("\t");
+               for (j = 0; j < 8; j++) {
+                       exptbl[i + j] = v;
+                       printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+                       v = gfmul(v, 2);
+                       if (v == 1)
+                               v = 0;  /* For entry 255, not a real entry */
+               }
+       }
+       printf("};\n");
+
+       /* Compute inverse table x^-1 == x^254 */
+       printf("\nconst u8 __attribute__((aligned(256)))\n"
+              "raid6_gfinv[256] =\n" "{\n");
+       for (i = 0; i < 256; i += 8) {
+               printf("\t");
+               for (j = 0; j < 8; j++) {
+                       invtbl[i + j] = v = gfpow(i + j, 254);
+                       printf("0x%02x,%c", v, (j == 7) ? '\n' : ' ');
+               }
+       }
+       printf("};\n");
+
+       /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
+       printf("\nconst u8 __attribute__((aligned(256)))\n"
+              "raid6_gfexi[256] =\n" "{\n");
+       for (i = 0; i < 256; i += 8) {
+               printf("\t");
+               for (j = 0; j < 8; j++)
+                       printf("0x%02x,%c", invtbl[exptbl[i + j] ^ 1],
+                              (j == 7) ? '\n' : ' ');
+       }
+       printf("};\n");
+
+       return 0;
 }
index eb631eb..3f299d8 100644 (file)
@@ -436,7 +436,7 @@ static int multipath_run (mddev_t *mddev)
        }
 
        conf->working_disks = 0;
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                disk_idx = rdev->raid_disk;
                if (disk_idx < 0 ||
                    disk_idx >= mddev->raid_disks)
index f8e5917..818b482 100644 (file)
@@ -72,11 +72,11 @@ static int create_strip_zones (mddev_t *mddev)
         */
        conf->nr_strip_zones = 0;
  
-       ITERATE_RDEV(mddev,rdev1,tmp1) {
+       rdev_for_each(rdev1, tmp1, mddev) {
                printk("raid0: looking at %s\n",
                        bdevname(rdev1->bdev,b));
                c = 0;
-               ITERATE_RDEV(mddev,rdev2,tmp2) {
+               rdev_for_each(rdev2, tmp2, mddev) {
                        printk("raid0:   comparing %s(%llu)",
                               bdevname(rdev1->bdev,b),
                               (unsigned long long)rdev1->size);
@@ -124,7 +124,7 @@ static int create_strip_zones (mddev_t *mddev)
        cnt = 0;
        smallest = NULL;
        zone->dev = conf->devlist;
-       ITERATE_RDEV(mddev, rdev1, tmp1) {
+       rdev_for_each(rdev1, tmp1, mddev) {
                int j = rdev1->raid_disk;
 
                if (j < 0 || j >= mddev->raid_disks) {
@@ -293,7 +293,7 @@ static int raid0_run (mddev_t *mddev)
 
        /* calculate array device size */
        mddev->array_size = 0;
-       ITERATE_RDEV(mddev,rdev,tmp)
+       rdev_for_each(rdev, tmp, mddev)
                mddev->array_size += rdev->size;
 
        printk("raid0 : md_size is %llu blocks.\n", 
index 4a69c41..5c7fef0 100644 (file)
@@ -1684,6 +1684,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        if (!go_faster && conf->nr_waiting)
                msleep_interruptible(1000);
 
+       bitmap_cond_end_sync(mddev->bitmap, sector_nr);
        raise_barrier(conf);
 
        conf->next_resync = sector_nr;
@@ -1766,6 +1767,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                return rv;
        }
 
+       if (max_sector > mddev->resync_max)
+               max_sector = mddev->resync_max; /* Don't do IO beyond here */
        nr_sectors = 0;
        sync_blocks = 0;
        do {
@@ -1884,7 +1887,7 @@ static int run(mddev_t *mddev)
        if (!conf->r1bio_pool)
                goto out_no_mem;
 
-       ITERATE_RDEV(mddev, rdev, tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
                    || disk_idx < 0)
index 5cdcc93..017f581 100644 (file)
@@ -1657,6 +1657,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                return (max_sector - sector_nr) + sectors_skipped;
        }
 
+       if (max_sector > mddev->resync_max)
+               max_sector = mddev->resync_max; /* Don't do IO beyond here */
+
        /* make sure whole request will fit in a chunk - if chunks
         * are meaningful
         */
@@ -1670,6 +1673,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        if (!go_faster && conf->nr_waiting)
                msleep_interruptible(1000);
 
+       bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
        /* Again, very different code for resync and recovery.
         * Both must result in an r10bio with a list of bios that
         * have bi_end_io, bi_sector, bi_bdev set,
@@ -2021,7 +2026,7 @@ static int run(mddev_t *mddev)
                goto out_free_conf;
        }
 
-       ITERATE_RDEV(mddev, rdev, tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                disk_idx = rdev->raid_disk;
                if (disk_idx >= mddev->raid_disks
                    || disk_idx < 0)
index e8c8157..2d6f1a5 100644 (file)
@@ -3159,7 +3159,8 @@ static void raid5_activate_delayed(raid5_conf_t *conf)
                                atomic_inc(&conf->preread_active_stripes);
                        list_add_tail(&sh->lru, &conf->handle_list);
                }
-       }
+       } else
+               blk_plug_device(conf->mddev->queue);
 }
 
 static void activate_bit_delay(raid5_conf_t *conf)
@@ -3549,7 +3550,8 @@ static int make_request(struct request_queue *q, struct bio * bi)
                                goto retry;
                        }
                        finish_wait(&conf->wait_for_overlap, &w);
-                       handle_stripe(sh, NULL);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       clear_bit(STRIPE_DELAYED, &sh->state);
                        release_stripe(sh);
                } else {
                        /* cannot get stripe for read-ahead, just give-up */
@@ -3698,6 +3700,25 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                release_stripe(sh);
                first_sector += STRIPE_SECTORS;
        }
+       /* If this takes us to the resync_max point where we have to pause,
+        * then we need to write out the superblock.
+        */
+       sector_nr += conf->chunk_size>>9;
+       if (sector_nr >= mddev->resync_max) {
+               /* Cannot proceed until we've updated the superblock... */
+               wait_event(conf->wait_for_overlap,
+                          atomic_read(&conf->reshape_stripes) == 0);
+               mddev->reshape_position = conf->expand_progress;
+               set_bit(MD_CHANGE_DEVS, &mddev->flags);
+               md_wakeup_thread(mddev->thread);
+               wait_event(mddev->sb_wait,
+                          !test_bit(MD_CHANGE_DEVS, &mddev->flags)
+                          || kthread_should_stop());
+               spin_lock_irq(&conf->device_lock);
+               conf->expand_lo = mddev->reshape_position;
+               spin_unlock_irq(&conf->device_lock);
+               wake_up(&conf->wait_for_overlap);
+       }
        return conf->chunk_size>>9;
 }
 
@@ -3734,6 +3755,12 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
        if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
                return reshape_request(mddev, sector_nr, skipped);
 
+       /* No need to check resync_max as we never do more than one
+        * stripe, and as resync_max will always be on a chunk boundary,
+        * if the check in md_do_sync didn't fire, there is no chance
+        * of overstepping resync_max here
+        */
+
        /* if there is too many failed drives and we are trying
         * to resync, then assert that we are finished, because there is
         * nothing we can do.
@@ -3753,6 +3780,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
                return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */
        }
 
+
+       bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
        pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks);
        sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1);
        if (sh == NULL) {
@@ -3864,7 +3894,7 @@ static int  retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
  * During the scan, completed stripes are saved for us by the interrupt
  * handler, so that they will not have to wait for our next wakeup.
  */
-static void raid5d (mddev_t *mddev)
+static void raid5d(mddev_t *mddev)
 {
        struct stripe_head *sh;
        raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3889,12 +3919,6 @@ static void raid5d (mddev_t *mddev)
                        activate_bit_delay(conf);
                }
 
-               if (list_empty(&conf->handle_list) &&
-                   atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD &&
-                   !blk_queue_plugged(mddev->queue) &&
-                   !list_empty(&conf->delayed_list))
-                       raid5_activate_delayed(conf);
-
                while ((bio = remove_bio_from_retry(conf))) {
                        int ok;
                        spin_unlock_irq(&conf->device_lock);
@@ -4108,7 +4132,7 @@ static int run(mddev_t *mddev)
 
        pr_debug("raid5: run(%s) called.\n", mdname(mddev));
 
-       ITERATE_RDEV(mddev,rdev,tmp) {
+       rdev_for_each(rdev, tmp, mddev) {
                raid_disk = rdev->raid_disk;
                if (raid_disk >= conf->raid_disks
                    || raid_disk < 0)
@@ -4521,7 +4545,7 @@ static int raid5_start_reshape(mddev_t *mddev)
        if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                return -EBUSY;
 
-       ITERATE_RDEV(mddev, rdev, rtmp)
+       rdev_for_each(rdev, rtmp, mddev)
                if (rdev->raid_disk < 0 &&
                    !test_bit(Faulty, &rdev->flags))
                        spares++;
@@ -4543,7 +4567,7 @@ static int raid5_start_reshape(mddev_t *mddev)
        /* Add some new drives, as many as will fit.
         * We know there are enough to make the newly sized array work.
         */
-       ITERATE_RDEV(mddev, rdev, rtmp)
+       rdev_for_each(rdev, rtmp, mddev)
                if (rdev->raid_disk < 0 &&
                    !test_bit(Faulty, &rdev->flags)) {
                        if (raid5_add_disk(mddev, rdev)) {
index 0d5cd57..559cc41 100644 (file)
@@ -1,12 +1,10 @@
 /* -*- linux-c -*- ------------------------------------------------------- *
  *
- *   Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2002-2007 H. Peter Anvin - 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, Inc., 53 Temple Place Ste 330,
- *   Bostom MA 02111-1307, USA; either version 2 of the License, or
- *   (at your option) any later version; incorporated herein by reference.
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2 or (at your
+ *   option) any later version; incorporated herein by reference.
  *
  * ----------------------------------------------------------------------- */
 
@@ -30,67 +28,87 @@ char *dataptrs[NDISKS];
 char data[NDISKS][PAGE_SIZE];
 char recovi[PAGE_SIZE], recovj[PAGE_SIZE];
 
-void makedata(void)
+static void makedata(void)
 {
        int i, j;
 
-       for (  i = 0 ; i < NDISKS ; i++ ) {
-               for ( j = 0 ; j < PAGE_SIZE ; j++ ) {
+       for (i = 0; i < NDISKS; i++) {
+               for (j = 0; j < PAGE_SIZE; j++)
                        data[i][j] = rand();
-               }
+
                dataptrs[i] = data[i];
        }
 }
 
+static char disk_type(int d)
+{
+       switch (d) {
+       case NDISKS-2:
+               return 'P';
+       case NDISKS-1:
+               return 'Q';
+       default:
+               return 'D';
+       }
+}
+
+static int test_disks(int i, int j)
+{
+       int erra, errb;
+
+       memset(recovi, 0xf0, PAGE_SIZE);
+       memset(recovj, 0xba, PAGE_SIZE);
+
+       dataptrs[i] = recovi;
+       dataptrs[j] = recovj;
+
+       raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
+
+       erra = memcmp(data[i], recovi, PAGE_SIZE);
+       errb = memcmp(data[j], recovj, PAGE_SIZE);
+
+       if (i < NDISKS-2 && j == NDISKS-1) {
+               /* We don't implement the DQ failure scenario, since it's
+                  equivalent to a RAID-5 failure (XOR, then recompute Q) */
+               erra = errb = 0;
+       } else {
+               printf("algo=%-8s  faila=%3d(%c)  failb=%3d(%c)  %s\n",
+                      raid6_call.name,
+                      i, disk_type(i),
+                      j, disk_type(j),
+                      (!erra && !errb) ? "OK" :
+                      !erra ? "ERRB" :
+                      !errb ? "ERRA" : "ERRAB");
+       }
+
+       dataptrs[i] = data[i];
+       dataptrs[j] = data[j];
+
+       return erra || errb;
+}
+
 int main(int argc, char *argv[])
 {
-       const struct raid6_calls * const * algo;
+       const struct raid6_calls *const *algo;
        int i, j;
-       int erra, errb;
+       int err = 0;
 
        makedata();
 
-       for ( algo = raid6_algos ; *algo ; algo++ ) {
-               if ( !(*algo)->valid || (*algo)->valid() ) {
+       for (algo = raid6_algos; *algo; algo++) {
+               if (!(*algo)->valid || (*algo)->valid()) {
                        raid6_call = **algo;
 
                        /* Nuke syndromes */
                        memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
 
                        /* Generate assumed good syndrome */
-                       raid6_call.gen_syndrome(NDISKS, PAGE_SIZE, (void **)&dataptrs);
-
-                       for ( i = 0 ; i < NDISKS-1 ; i++ ) {
-                               for ( j = i+1 ; j < NDISKS ; j++ ) {
-                                       memset(recovi, 0xf0, PAGE_SIZE);
-                                       memset(recovj, 0xba, PAGE_SIZE);
-
-                                       dataptrs[i] = recovi;
-                                       dataptrs[j] = recovj;
-
-                                       raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs);
-
-                                       erra = memcmp(data[i], recovi, PAGE_SIZE);
-                                       errb = memcmp(data[j], recovj, PAGE_SIZE);
-
-                                       if ( i < NDISKS-2 && j == NDISKS-1 ) {
-                                               /* We don't implement the DQ failure scenario, since it's
-                                                  equivalent to a RAID-5 failure (XOR, then recompute Q) */
-                                       } else {
-                                               printf("algo=%-8s  faila=%3d(%c)  failb=%3d(%c)  %s\n",
-                                                      raid6_call.name,
-                                                      i, (i==NDISKS-2)?'P':'D',
-                                                      j, (j==NDISKS-1)?'Q':(j==NDISKS-2)?'P':'D',
-                                                      (!erra && !errb) ? "OK" :
-                                                      !erra ? "ERRB" :
-                                                      !errb ? "ERRA" :
-                                                      "ERRAB");
-                                       }
-
-                                       dataptrs[i] = data[i];
-                                       dataptrs[j] = data[j];
-                               }
-                       }
+                       raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
+                                               (void **)&dataptrs);
+
+                       for (i = 0; i < NDISKS-1; i++)
+                               for (j = i+1; j < NDISKS; j++)
+                                       err += test_disks(i, j);
                }
                printf("\n");
        }
@@ -99,5 +117,8 @@ int main(int argc, char *argv[])
        /* Pick the best algorithm test */
        raid6_select_algo();
 
-       return 0;
+       if (err)
+               printf("\n*** ERRORS FOUND ***\n");
+
+       return err;
 }
index 28ddd14..850b8c6 100644 (file)
@@ -22,7 +22,6 @@ obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
deleted file mode 100644 (file)
index 9fa5b70..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/kdev_t.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-
-#include <asm/semaphore.h>
-#include <asm/uaccess.h>
-
-
-#define DEV_MAX  4
-
-static int devnr = -1;
-module_param(devnr, int, 0644);
-
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/* ----------------------------------------------------------------------- */
-
-struct TVMIXER {
-       struct i2c_client *dev;
-       int minor;
-       int count;
-};
-
-static struct TVMIXER devices[DEV_MAX];
-
-static int tvmixer_adapters(struct i2c_adapter *adap);
-static int tvmixer_clients(struct i2c_client *client);
-
-/* ----------------------------------------------------------------------- */
-
-static int mix_to_v4l(int i)
-{
-       int r;
-
-       r = ((i & 0xff) * 65536 + 50) / 100;
-       if (r > 65535) r = 65535;
-       if (r <     0) r =     0;
-       return r;
-}
-
-static int v4l_to_mix(int i)
-{
-       int r;
-
-       r = (i * 100 + 32768) / 65536;
-       if (r > 100) r = 100;
-       if (r <   0) r =   0;
-       return r | (r << 8);
-}
-
-static int v4l_to_mix2(int l, int r)
-{
-       r = (r * 100 + 32768) / 65536;
-       if (r > 100) r = 100;
-       if (r <   0) r =   0;
-       l = (l * 100 + 32768) / 65536;
-       if (l > 100) l = 100;
-       if (l <   0) l =   0;
-       return (r << 8) | l;
-}
-
-static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct video_audio va;
-       int left,right,ret,val = 0;
-       struct TVMIXER *mix = file->private_data;
-       struct i2c_client *client = mix->dev;
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-
-       if (NULL == client)
-               return -ENODEV;
-
-       if (cmd == SOUND_MIXER_INFO) {
-               mixer_info info;
-               strlcpy(info.id, "tv card", sizeof(info.id));
-               strlcpy(info.name, client->name, sizeof(info.name));
-               info.modify_counter = 42 /* FIXME */;
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == SOUND_OLD_MIXER_INFO) {
-               _old_mixer_info info;
-               strlcpy(info.id, "tv card", sizeof(info.id));
-               strlcpy(info.name, client->name, sizeof(info.name));
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, p);
-
-       if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-               if (get_user(val, p))
-                       return -EFAULT;
-
-       /* read state */
-       memset(&va,0,sizeof(va));
-       client->driver->command(client,VIDIOCGAUDIO,&va);
-
-       switch (cmd) {
-       case MIXER_READ(SOUND_MIXER_RECMASK):
-       case MIXER_READ(SOUND_MIXER_CAPS):
-       case MIXER_READ(SOUND_MIXER_RECSRC):
-       case MIXER_WRITE(SOUND_MIXER_RECSRC):
-               ret = 0;
-               break;
-
-       case MIXER_READ(SOUND_MIXER_STEREODEVS):
-               ret = SOUND_MASK_VOLUME;
-               break;
-       case MIXER_READ(SOUND_MIXER_DEVMASK):
-               ret = SOUND_MASK_VOLUME;
-               if (va.flags & VIDEO_AUDIO_BASS)
-                       ret |= SOUND_MASK_BASS;
-               if (va.flags & VIDEO_AUDIO_TREBLE)
-                       ret |= SOUND_MASK_TREBLE;
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_VOLUME):
-               left  = mix_to_v4l(val);
-               right = mix_to_v4l(val >> 8);
-               va.volume  = max(left,right);
-               va.balance = (32768*min(left,right)) / (va.volume ? va.volume : 1);
-               va.balance = (left<right) ? (65535-va.balance) : va.balance;
-               if (va.volume)
-                       va.flags &= ~VIDEO_AUDIO_MUTE;
-               client->driver->command(client,VIDIOCSAUDIO,&va);
-               client->driver->command(client,VIDIOCGAUDIO,&va);
-               /* fall throuth */
-       case MIXER_READ(SOUND_MIXER_VOLUME):
-               left  = (min(65536 - va.balance,32768) *
-                        va.volume) / 32768;
-               right = (min(va.balance,(u16)32768) *
-                        va.volume) / 32768;
-               ret = v4l_to_mix2(left,right);
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_BASS):
-               va.bass = mix_to_v4l(val);
-               client->driver->command(client,VIDIOCSAUDIO,&va);
-               client->driver->command(client,VIDIOCGAUDIO,&va);
-               /* fall throuth  */
-       case MIXER_READ(SOUND_MIXER_BASS):
-               ret = v4l_to_mix(va.bass);
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_TREBLE):
-               va.treble = mix_to_v4l(val);
-               client->driver->command(client,VIDIOCSAUDIO,&va);
-               client->driver->command(client,VIDIOCGAUDIO,&va);
-               /* fall throuth */
-       case MIXER_READ(SOUND_MIXER_TREBLE):
-               ret = v4l_to_mix(va.treble);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       if (put_user(ret, p))
-               return -EFAULT;
-       return 0;
-}
-
-static int tvmixer_open(struct inode *inode, struct file *file)
-{
-       int i, minor = iminor(inode);
-       struct TVMIXER *mix = NULL;
-       struct i2c_client *client = NULL;
-
-       for (i = 0; i < DEV_MAX; i++) {
-               if (devices[i].minor == minor) {
-                       mix = devices+i;
-                       client = mix->dev;
-                       break;
-               }
-       }
-
-       if (NULL == client)
-               return -ENODEV;
-
-       /* lock bttv in memory while the mixer is in use  */
-       file->private_data = mix;
-       if (client->adapter->owner)
-               try_module_get(client->adapter->owner);
-       return 0;
-}
-
-static int tvmixer_release(struct inode *inode, struct file *file)
-{
-       struct TVMIXER *mix = file->private_data;
-       struct i2c_client *client;
-
-       client = mix->dev;
-       if (NULL == client) {
-               return -ENODEV;
-       }
-
-       module_put(client->adapter->owner);
-       return 0;
-}
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name    = "tvmixer",
-       },
-       .id              = I2C_DRIVERID_TVMIXER,
-       .detach_adapter  = tvmixer_adapters,
-       .attach_adapter  = tvmixer_adapters,
-       .detach_client   = tvmixer_clients,
-};
-
-static const struct file_operations tvmixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .ioctl          = tvmixer_ioctl,
-       .open           = tvmixer_open,
-       .release        = tvmixer_release,
-};
-
-/* ----------------------------------------------------------------------- */
-
-static int tvmixer_adapters(struct i2c_adapter *adap)
-{
-       struct i2c_client *client;
-
-       list_for_each_entry(client, &adap->clients, list)
-               tvmixer_clients(client);
-       return 0;
-}
-
-static int tvmixer_clients(struct i2c_client *client)
-{
-       struct video_audio va;
-       int i,minor;
-
-       if (!(client->adapter->class & I2C_CLASS_TV_ANALOG))
-               return -1;
-
-       /* unregister ?? */
-       for (i = 0; i < DEV_MAX; i++) {
-               if (devices[i].dev == client) {
-                       /* unregister */
-                       unregister_sound_mixer(devices[i].minor);
-                       devices[i].dev = NULL;
-                       devices[i].minor = -1;
-                       printk("tvmixer: %s unregistered (#1)\n",
-                              client->name);
-                       return 0;
-               }
-       }
-
-       /* look for a free slot */
-       for (i = 0; i < DEV_MAX; i++)
-               if (NULL == devices[i].dev)
-                       break;
-       if (i == DEV_MAX) {
-               printk(KERN_WARNING "tvmixer: DEV_MAX too small\n");
-               return -1;
-       }
-
-       /* audio chip with mixer ??? */
-       if (NULL == client->driver->command)
-               return -1;
-       memset(&va,0,sizeof(va));
-       if (0 != client->driver->command(client,VIDIOCGAUDIO,&va))
-               return -1;
-       if (0 == (va.flags & VIDEO_AUDIO_VOLUME))
-               return -1;
-
-       /* everything is fine, register */
-       if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
-               printk(KERN_ERR "tvmixer: cannot allocate mixer device\n");
-               return -1;
-       }
-
-       devices[i].minor = minor;
-       devices[i].count = 0;
-       devices[i].dev   = client;
-       printk("tvmixer: %s (%s) registered with minor %d\n",
-              client->name,client->adapter->name,minor);
-
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int __init tvmixer_init_module(void)
-{
-       int i;
-
-       for (i = 0; i < DEV_MAX; i++)
-               devices[i].minor = -1;
-
-       return i2c_add_driver(&driver);
-}
-
-static void __exit tvmixer_cleanup_module(void)
-{
-       int i;
-
-       i2c_del_driver(&driver);
-       for (i = 0; i < DEV_MAX; i++) {
-               if (devices[i].minor != -1) {
-                       unregister_sound_mixer(devices[i].minor);
-                       printk("tvmixer: %s unregistered (#2)\n",
-                              devices[i].dev->name);
-               }
-       }
-}
-
-module_init(tvmixer_init_module);
-module_exit(tvmixer_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 7dce318..0846c33 100644 (file)
@@ -33,7 +33,6 @@
  *  Sam Lin        - GPS support
  */
 
-#include <linux/autoconf.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
index c8d62c2..1cfd7f3 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/dmi.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
-#include <linux/autoconf.h>
 
 #define FUJITSU_DRIVER_VERSION "0.3"
 
index 552b795..c884730 100644 (file)
@@ -129,27 +129,28 @@ module_param(cpoint_count, int, 0644);
 MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\
                                "crash point is to be hit to trigger action");
 
-unsigned int jp_do_irq(unsigned int irq)
+static unsigned int jp_do_irq(unsigned int irq)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action)
+static irqreturn_t jp_handle_irq_event(unsigned int irq,
+                                      struct irqaction *action)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-void jp_tasklet_action(struct softirq_action *a)
+static void jp_tasklet_action(struct softirq_action *a)
 {
        lkdtm_handler();
        jprobe_return();
 }
 
-void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
+static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
 {
        lkdtm_handler();
        jprobe_return();
@@ -157,23 +158,24 @@ void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
 
 struct scan_control;
 
-unsigned long jp_shrink_inactive_list(unsigned long max_scan,
-                               struct zone *zone, struct scan_control *sc)
+static unsigned long jp_shrink_inactive_list(unsigned long max_scan,
+                                            struct zone *zone,
+                                            struct scan_control *sc)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
-                               const enum hrtimer_mode mode)
+static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
+                           const enum hrtimer_mode mode)
 {
        lkdtm_handler();
        jprobe_return();
        return 0;
 }
 
-int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 {
        lkdtm_handler();
        jprobe_return();
@@ -270,7 +272,7 @@ void lkdtm_handler(void)
        }
 }
 
-int lkdtm_module_init(void)
+static int __init lkdtm_module_init(void)
 {
        int ret;
 
@@ -331,7 +333,7 @@ int lkdtm_module_init(void)
        return 0;
 }
 
-void lkdtm_module_exit(void)
+static void __exit lkdtm_module_exit(void)
 {
         unregister_jprobe(&lkdtm);
         printk(KERN_INFO "lkdtm : Crash point unregistered\n");
index 83679c7..de898c6 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/dmi.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
-#include <linux/autoconf.h>
 
 #define MSI_DRIVER_VERSION "0.5"
 
index cd221fd..7fa61e9 100644 (file)
@@ -25,7 +25,7 @@
 #include <asm/atomic.h>
 #include <asm/io.h>
 
-#define PHANTOM_VERSION                "n0.9.7"
+#define PHANTOM_VERSION                "n0.9.8"
 
 #define PHANTOM_MAX_MINORS     8
 
@@ -456,8 +456,9 @@ static int phantom_resume(struct pci_dev *pdev)
 #endif
 
 static struct pci_device_id phantom_pci_tbl[] __devinitdata = {
-       { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
-               .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
+       { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050,
+         .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050,
+         .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
index be4b994..eeaaa9d 100644 (file)
@@ -4,7 +4,7 @@
  * block2mtd.c - create an mtd from a block device
  *
  * Copyright (C) 2001,2002     Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004-2006     Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (C) 2004-2006     Joern Engel <joern@wh.fh-wedel.de>
  *
  * Licence: GPL
  */
@@ -485,5 +485,5 @@ module_init(block2mtd_init);
 module_exit(block2mtd_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk> and others");
+MODULE_AUTHOR("Joern Engel <joern@lazybastard.org>");
 MODULE_DESCRIPTION("Emulate an MTD using a block device");
index 56cc1ca..180298b 100644 (file)
@@ -2,7 +2,7 @@
  * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
  *
  * Copyright (c) ????          Jochen Schäuble <psionic@psionic.de>
- * Copyright (c) 2003-2004     Jörn Engel <joern@wh.fh-wedel.de>
+ * Copyright (c) 2003-2004     Joern Engel <joern@wh.fh-wedel.de>
  *
  * Usage:
  *
@@ -299,5 +299,5 @@ module_init(init_phram);
 module_exit(cleanup_phram);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
+MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>");
 MODULE_DESCRIPTION("MTD driver for physical RAM");
index d884f2b..2a8fde9 100644 (file)
@@ -4,7 +4,7 @@
  * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
  *
  * (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz>
- * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
+ * (C) 2005 Joern Engel <joern@wohnheim.fh-wedel.de>
  *
  */
 
index 3634223..d4843d0 100644 (file)
@@ -323,8 +323,8 @@ enum {
        NvRegMIIStatus = 0x180,
 #define NVREG_MIISTAT_ERROR            0x0001
 #define NVREG_MIISTAT_LINKCHANGE       0x0008
-#define NVREG_MIISTAT_MASK             0x000f
-#define NVREG_MIISTAT_MASK2            0x000f
+#define NVREG_MIISTAT_MASK_RW          0x0007
+#define NVREG_MIISTAT_MASK_ALL         0x000f
        NvRegMIIMask = 0x184,
 #define NVREG_MII_LINKCHANGE           0x0008
 
@@ -624,6 +624,9 @@ union ring_type {
 #define NV_MSI_X_VECTOR_TX    0x1
 #define NV_MSI_X_VECTOR_OTHER 0x2
 
+#define NV_RESTART_TX         0x1
+#define NV_RESTART_RX         0x2
+
 /* statistics */
 struct nv_ethtool_str {
        char name[ETH_GSTRING_LEN];
@@ -1061,7 +1064,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
        u32 reg;
        int retval;
 
-       writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_RW, base + NvRegMIIStatus);
 
        reg = readl(base + NvRegMIIControl);
        if (reg & NVREG_MIICTL_INUSE) {
@@ -1432,16 +1435,30 @@ static void nv_mac_reset(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
+       u32 temp1, temp2, temp3;
 
        dprintk(KERN_DEBUG "%s: nv_mac_reset\n", dev->name);
+
        writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
        pci_push(base);
+
+       /* save registers since they will be cleared on reset */
+       temp1 = readl(base + NvRegMacAddrA);
+       temp2 = readl(base + NvRegMacAddrB);
+       temp3 = readl(base + NvRegTransmitPoll);
+
        writel(NVREG_MAC_RESET_ASSERT, base + NvRegMacReset);
        pci_push(base);
        udelay(NV_MAC_RESET_DELAY);
        writel(0, base + NvRegMacReset);
        pci_push(base);
        udelay(NV_MAC_RESET_DELAY);
+
+       /* restore saved registers */
+       writel(temp1, base + NvRegMacAddrA);
+       writel(temp2, base + NvRegMacAddrB);
+       writel(temp3, base + NvRegTransmitPoll);
+
        writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
        pci_push(base);
 }
@@ -2767,6 +2784,7 @@ static int nv_update_linkspeed(struct net_device *dev)
        int mii_status;
        int retval = 0;
        u32 control_1000, status_1000, phyreg, pause_flags, txreg;
+       u32 txrxFlags = 0;
 
        /* BMSR_LSTATUS is latched, read it twice:
         * we want the current value.
@@ -2862,6 +2880,16 @@ set_speed:
        np->duplex = newdup;
        np->linkspeed = newls;
 
+       /* The transmitter and receiver must be restarted for safe update */
+       if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START) {
+               txrxFlags |= NV_RESTART_TX;
+               nv_stop_tx(dev);
+       }
+       if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
+               txrxFlags |= NV_RESTART_RX;
+               nv_stop_rx(dev);
+       }
+
        if (np->gigabit == PHY_GIGABIT) {
                phyreg = readl(base + NvRegRandomSeed);
                phyreg &= ~(0x3FF00);
@@ -2950,6 +2978,11 @@ set_speed:
        }
        nv_update_pause(dev, pause_flags);
 
+       if (txrxFlags & NV_RESTART_TX)
+               nv_start_tx(dev);
+       if (txrxFlags & NV_RESTART_RX)
+               nv_start_rx(dev);
+
        return retval;
 }
 
@@ -2976,7 +3009,7 @@ static void nv_link_irq(struct net_device *dev)
        u32 miistat;
 
        miistat = readl(base + NvRegMIIStatus);
-       writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_LINKCHANGE, base + NvRegMIIStatus);
        dprintk(KERN_INFO "%s: link change irq, status 0x%x.\n", dev->name, miistat);
 
        if (miistat & (NVREG_MIISTAT_LINKCHANGE))
@@ -4851,7 +4884,7 @@ static int nv_open(struct net_device *dev)
 
        writel(0, base + NvRegMIIMask);
        writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
-       writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
 
        writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
        writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
@@ -4889,7 +4922,7 @@ static int nv_open(struct net_device *dev)
 
        nv_disable_hw_interrupts(dev, np->irqmask);
        pci_push(base);
-       writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
        writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
        pci_push(base);
 
@@ -4912,7 +4945,7 @@ static int nv_open(struct net_device *dev)
        {
                u32 miistat;
                miistat = readl(base + NvRegMIIStatus);
-               writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+               writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
                dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
        }
        /* set linkspeed to invalid value, thus force nv_update_linkspeed
@@ -5280,7 +5313,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                phystate &= ~NVREG_ADAPTCTL_RUNNING;
                writel(phystate, base + NvRegAdapterControl);
        }
-       writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+       writel(NVREG_MIISTAT_MASK_ALL, base + NvRegMIIStatus);
 
        if (id->driver_data & DEV_HAS_MGMT_UNIT) {
                /* management unit running on the mac? */
index 100bf41..6a647d9 100644 (file)
@@ -127,7 +127,7 @@ int gfar_mdio_reset(struct mii_bus *bus)
        struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
        unsigned int timeout = PHY_INIT_TIMEOUT;
 
-       spin_lock_bh(&bus->mdio_lock);
+       mutex_lock(&bus->mdio_lock);
 
        /* Reset the management interface */
        gfar_write(&regs->miimcfg, MIIMCFG_RESET);
@@ -140,7 +140,7 @@ int gfar_mdio_reset(struct mii_bus *bus)
                        timeout--)
                cpu_relax();
 
-       spin_unlock_bh(&bus->mdio_lock);
+       mutex_unlock(&bus->mdio_lock);
 
        if(timeout <= 0) {
                printk(KERN_ERR "%s: The MII Bus is stuck!\n",
index 419861c..58d3bb6 100644 (file)
@@ -1020,7 +1020,7 @@ static const struct ethtool_ops ops = {
        .get_link = veth_get_link,
 };
 
-static struct net_device * __init veth_probe_one(int vlan,
+static struct net_device *veth_probe_one(int vlan,
                struct vio_dev *vio_dev)
 {
        struct net_device *dev;
index a021a6e..d0bf206 100644 (file)
@@ -136,8 +136,6 @@ struct ixgbe_ring {
        u16 head;
        u16 tail;
 
-       /* To protect race between sender and clean_tx_irq */
-       spinlock_t tx_lock;
 
        struct ixgbe_queue_stats stats;
 
@@ -174,7 +172,6 @@ struct ixgbe_adapter {
        struct vlan_group *vlgrp;
        u16 bd_number;
        u16 rx_buf_len;
-       atomic_t irq_sem;
        struct work_struct reset_task;
 
        /* TX */
@@ -244,6 +241,7 @@ extern const char ixgbe_driver_version[];
 
 extern int ixgbe_up(struct ixgbe_adapter *adapter);
 extern void ixgbe_down(struct ixgbe_adapter *adapter);
+extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter);
 extern void ixgbe_reset(struct ixgbe_adapter *adapter);
 extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
index 3635344..a119cbd 100644 (file)
@@ -103,21 +103,41 @@ static int ixgbe_get_settings(struct net_device *netdev,
                              struct ethtool_cmd *ecmd)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 link_speed = 0;
+       bool link_up;
 
-       ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
-       ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
-       ecmd->port = PORT_FIBRE;
+       ecmd->supported = SUPPORTED_10000baseT_Full;
+       ecmd->autoneg = AUTONEG_ENABLE;
        ecmd->transceiver = XCVR_EXTERNAL;
+       if (hw->phy.media_type == ixgbe_media_type_copper) {
+               ecmd->supported |= (SUPPORTED_1000baseT_Full |
+                                   SUPPORTED_TP | SUPPORTED_Autoneg);
+
+               ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg);
+               if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+                       ecmd->advertising |= ADVERTISED_10000baseT_Full;
+               if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
+                       ecmd->advertising |= ADVERTISED_1000baseT_Full;
+
+               ecmd->port = PORT_TP;
+       } else {
+               ecmd->supported |= SUPPORTED_FIBRE;
+               ecmd->advertising = (ADVERTISED_10000baseT_Full |
+                                    ADVERTISED_FIBRE);
+               ecmd->port = PORT_FIBRE;
+       }
 
-       if (netif_carrier_ok(adapter->netdev)) {
-               ecmd->speed = SPEED_10000;
+       adapter->hw.mac.ops.check_link(hw, &(link_speed), &link_up);
+       if (link_up) {
+               ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+                               SPEED_10000 : SPEED_1000;
                ecmd->duplex = DUPLEX_FULL;
        } else {
                ecmd->speed = -1;
                ecmd->duplex = -1;
        }
 
-       ecmd->autoneg = AUTONEG_DISABLE;
        return 0;
 }
 
@@ -125,17 +145,17 @@ static int ixgbe_set_settings(struct net_device *netdev,
                              struct ethtool_cmd *ecmd)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
 
-       if (ecmd->autoneg == AUTONEG_ENABLE ||
-           ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
-               return -EINVAL;
-
-       if (netif_running(adapter->netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_reset(adapter);
-               ixgbe_up(adapter);
-       } else {
-               ixgbe_reset(adapter);
+       switch (hw->phy.media_type) {
+       case ixgbe_media_type_fiber:
+               if ((ecmd->autoneg == AUTONEG_ENABLE) ||
+                   (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
+                       return -EINVAL;
+               /* in this case we currently only support 10Gb/FULL */
+               break;
+       default:
+               break;
        }
 
        return 0;
@@ -147,7 +167,7 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 
-       pause->autoneg = AUTONEG_DISABLE;
+       pause->autoneg = (hw->fc.type == ixgbe_fc_full ? 1 : 0);
 
        if (hw->fc.type == ixgbe_fc_rx_pause) {
                pause->rx_pause = 1;
@@ -165,10 +185,8 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 
-       if (pause->autoneg == AUTONEG_ENABLE)
-               return -EINVAL;
-
-       if (pause->rx_pause && pause->tx_pause)
+       if ((pause->autoneg == AUTONEG_ENABLE) ||
+           (pause->rx_pause && pause->tx_pause))
                hw->fc.type = ixgbe_fc_full;
        else if (pause->rx_pause && !pause->tx_pause)
                hw->fc.type = ixgbe_fc_rx_pause;
@@ -176,15 +194,15 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
                hw->fc.type = ixgbe_fc_tx_pause;
        else if (!pause->rx_pause && !pause->tx_pause)
                hw->fc.type = ixgbe_fc_none;
+       else
+               return -EINVAL;
 
        hw->fc.original_type = hw->fc.type;
 
-       if (netif_running(adapter->netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_up(adapter);
-       } else {
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
+       else
                ixgbe_reset(adapter);
-       }
 
        return 0;
 }
@@ -203,12 +221,10 @@ static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
        else
                adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
 
-       if (netif_running(netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_up(adapter);
-       } else {
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
+       else
                ixgbe_reset(adapter);
-       }
 
        return 0;
 }
@@ -662,7 +678,10 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
                return 0;
        }
 
-       if (netif_running(adapter->netdev))
+       while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
+               msleep(1);
+
+       if (netif_running(netdev))
                ixgbe_down(adapter);
 
        /*
@@ -733,6 +752,7 @@ err_setup:
        if (netif_running(adapter->netdev))
                ixgbe_up(adapter);
 
+       clear_bit(__IXGBE_RESETTING, &adapter->state);
        return err;
 }
 
@@ -820,11 +840,8 @@ static int ixgbe_nway_reset(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-       if (netif_running(netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_reset(adapter);
-               ixgbe_up(adapter);
-       }
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
 
        return 0;
 }
index 3732dd6..ead49e5 100644 (file)
@@ -87,6 +87,25 @@ MODULE_VERSION(DRV_VERSION);
 
 #define DEFAULT_DEBUG_LEVEL_SHIFT 3
 
+static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
+{
+       u32 ctrl_ext;
+
+       /* Let firmware take over control of h/w */
+       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+                       ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+}
+
+static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
+{
+       u32 ctrl_ext;
+
+       /* Let firmware know the driver has taken over */
+       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+                       ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+}
 
 #ifdef DEBUG
 /**
@@ -165,6 +184,15 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
        return false;
 }
 
+#define IXGBE_MAX_TXD_PWR      14
+#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+                        (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+       MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1)   /* for context */
+
 /**
  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
  * @adapter: board private structure
@@ -177,18 +205,34 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        struct ixgbe_tx_buffer *tx_buffer_info;
        unsigned int i, eop;
        bool cleaned = false;
-       int count = 0;
+       unsigned int total_tx_bytes = 0, total_tx_packets = 0;
 
        i = tx_ring->next_to_clean;
        eop = tx_ring->tx_buffer_info[i].next_to_watch;
        eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
        while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) {
-               for (cleaned = false; !cleaned;) {
+               cleaned = false;
+               while (!cleaned) {
                        tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
                        tx_buffer_info = &tx_ring->tx_buffer_info[i];
                        cleaned = (i == eop);
 
                        tx_ring->stats.bytes += tx_buffer_info->length;
+                       if (cleaned) {
+                               struct sk_buff *skb = tx_buffer_info->skb;
+#ifdef NETIF_F_TSO
+                               unsigned int segs, bytecount;
+                               segs = skb_shinfo(skb)->gso_segs ?: 1;
+                               /* multiply data chunks by size of headers */
+                               bytecount = ((segs - 1) * skb_headlen(skb)) +
+                                           skb->len;
+                               total_tx_packets += segs;
+                               total_tx_bytes += bytecount;
+#else
+                               total_tx_packets++;
+                               total_tx_bytes += skb->len;
+#endif
+                       }
                        ixgbe_unmap_and_free_tx_resource(adapter,
                                                         tx_buffer_info);
                        tx_desc->wb.status = 0;
@@ -204,29 +248,36 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
                eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
 
                /* weight of a sort for tx, avoid endless transmit cleanup */
-               if (count++ >= tx_ring->work_limit)
+               if (total_tx_packets >= tx_ring->work_limit)
                        break;
        }
 
        tx_ring->next_to_clean = i;
 
-#define TX_WAKE_THRESHOLD 32
-       spin_lock(&tx_ring->tx_lock);
-
-       if (cleaned && netif_carrier_ok(netdev) &&
-           (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) &&
-           !test_bit(__IXGBE_DOWN, &adapter->state))
-               netif_wake_queue(netdev);
-
-       spin_unlock(&tx_ring->tx_lock);
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+       if (total_tx_packets && netif_carrier_ok(netdev) &&
+           (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
+               /* Make sure that anybody stopping the queue after this
+                * sees the new next_to_clean.
+                */
+               smp_mb();
+               if (netif_queue_stopped(netdev) &&
+                   !test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       netif_wake_queue(netdev);
+                       adapter->restart_queue++;
+               }
+       }
 
        if (adapter->detect_tx_hung)
                if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc))
                        netif_stop_queue(netdev);
 
-       if (count >= tx_ring->work_limit)
+       if (total_tx_packets >= tx_ring->work_limit)
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value);
 
+       adapter->net_stats.tx_bytes += total_tx_bytes;
+       adapter->net_stats.tx_packets += total_tx_packets;
+       cleaned = total_tx_packets ? true : false;
        return cleaned;
 }
 
@@ -255,25 +306,40 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
        }
 }
 
+/**
+ * ixgbe_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @adapter: address of board private structure
+ * @status_err: hardware indication of status of receive
+ * @skb: skb currently being received and modified
+ **/
 static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
                                         u32 status_err,
                                         struct sk_buff *skb)
 {
        skb->ip_summed = CHECKSUM_NONE;
 
-       /* Ignore Checksum bit is set */
+       /* Ignore Checksum bit is set, or rx csum disabled */
        if ((status_err & IXGBE_RXD_STAT_IXSM) ||
-                    !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+           !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
                return;
-       /* TCP/UDP checksum error bit is set */
-       if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) {
-               /* let the stack verify checksum errors */
+
+       /* if IP and error */
+       if ((status_err & IXGBE_RXD_STAT_IPCS) &&
+           (status_err & IXGBE_RXDADV_ERR_IPE)) {
                adapter->hw_csum_rx_error++;
                return;
        }
+
+       if (!(status_err & IXGBE_RXD_STAT_L4CS))
+               return;
+
+       if (status_err & IXGBE_RXDADV_ERR_TCPE) {
+               adapter->hw_csum_rx_error++;
+               return;
+       }
+
        /* It must be a TCP or UDP packet with a valid checksum */
-       if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS))
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
        adapter->hw_csum_rx_good++;
 }
 
@@ -379,6 +445,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
        u16 hdr_info, vlan_tag;
        bool is_vlan, cleaned = false;
        int cleaned_count = 0;
+       unsigned int total_rx_bytes = 0, total_rx_packets = 0;
 
        i = rx_ring->next_to_clean;
        upper_len = 0;
@@ -458,6 +525,11 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
                }
 
                ixgbe_rx_checksum(adapter, staterr, skb);
+
+               /* probably a little skewed due to removing CRC */
+               total_rx_bytes += skb->len;
+               total_rx_packets++;
+
                skb->protocol = eth_type_trans(skb, netdev);
                ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
                netdev->last_rx = jiffies;
@@ -486,6 +558,9 @@ next_desc:
        if (cleaned_count)
                ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
 
+       adapter->net_stats.rx_bytes += total_rx_bytes;
+       adapter->net_stats.rx_packets += total_rx_packets;
+
        return cleaned;
 }
 
@@ -535,7 +610,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        mod_timer(&adapter->watchdog_timer, jiffies);
        }
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
 
        return IRQ_HANDLED;
 }
@@ -713,7 +790,6 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
        if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
                /* Disable interrupts and register for poll. The flush of the
                 * posted write is intentionally left out. */
-               atomic_inc(&adapter->irq_sem);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
                __netif_rx_schedule(netdev, &adapter->napi);
        }
@@ -801,7 +877,6 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
  **/
 static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
 {
-       atomic_inc(&adapter->irq_sem);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
        IXGBE_WRITE_FLUSH(&adapter->hw);
        synchronize_irq(adapter->pdev->irq);
@@ -813,15 +888,13 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
  **/
 static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
 {
-       if (atomic_dec_and_test(&adapter->irq_sem)) {
-               if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
-                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
-                                       (IXGBE_EIMS_ENABLE_MASK &
-                                        ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
-                               IXGBE_EIMS_ENABLE_MASK);
-               IXGBE_WRITE_FLUSH(&adapter->hw);
-       }
+       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
+                               (IXGBE_EIMS_ENABLE_MASK &
+                                ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+                       IXGBE_EIMS_ENABLE_MASK);
+       IXGBE_WRITE_FLUSH(&adapter->hw);
 }
 
 /**
@@ -1040,7 +1113,8 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        u32 ctrl;
 
-       ixgbe_irq_disable(adapter);
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_disable(adapter);
        adapter->vlgrp = grp;
 
        if (grp) {
@@ -1051,7 +1125,8 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
        }
 
-       ixgbe_irq_enable(adapter);
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_enable(adapter);
 }
 
 static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -1066,9 +1141,13 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-       ixgbe_irq_disable(adapter);
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_disable(adapter);
+
        vlan_group_set_device(adapter->vlgrp, vid, NULL);
-       ixgbe_irq_enable(adapter);
+
+       if (!test_bit(__IXGBE_DOWN, &adapter->state))
+               ixgbe_irq_enable(adapter);
 
        /* remove VID from filter table */
        ixgbe_set_vfta(&adapter->hw, vid, 0, false);
@@ -1170,6 +1249,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        u32 txdctl, rxdctl, mhadd;
        int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
 
+       ixgbe_get_hw_control(adapter);
+
        if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED |
                              IXGBE_FLAG_MSI_ENABLED)) {
                if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
@@ -1224,6 +1305,16 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        return 0;
 }
 
+void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
+{
+       WARN_ON(in_interrupt());
+       while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
+               msleep(1);
+       ixgbe_down(adapter);
+       ixgbe_up(adapter);
+       clear_bit(__IXGBE_RESETTING, &adapter->state);
+}
+
 int ixgbe_up(struct ixgbe_adapter *adapter)
 {
        /* hardware has been reset, we need to reload some things */
@@ -1408,7 +1499,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        msleep(10);
 
        napi_disable(&adapter->napi);
-       atomic_set(&adapter->irq_sem, 0);
 
        ixgbe_irq_disable(adapter);
 
@@ -1447,6 +1537,8 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_enable_wake(pdev, PCI_D3hot, 0);
        pci_enable_wake(pdev, PCI_D3cold, 0);
 
+       ixgbe_release_hw_control(adapter);
+
        pci_disable_device(pdev);
 
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -1481,7 +1573,8 @@ static int ixgbe_clean(struct napi_struct *napi, int budget)
        /* If budget not fully consumed, exit the polling mode */
        if (work_done < budget) {
                netif_rx_complete(netdev, napi);
-               ixgbe_irq_enable(adapter);
+               if (!test_bit(__IXGBE_DOWN, &adapter->state))
+                       ixgbe_irq_enable(adapter);
        }
 
        return work_done;
@@ -1506,8 +1599,7 @@ static void ixgbe_reset_task(struct work_struct *work)
 
        adapter->tx_timeout_count++;
 
-       ixgbe_down(adapter);
-       ixgbe_up(adapter);
+       ixgbe_reinit_locked(adapter);
 }
 
 /**
@@ -1590,7 +1682,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                return -ENOMEM;
        }
 
-       atomic_set(&adapter->irq_sem, 1);
        set_bit(__IXGBE_DOWN, &adapter->state);
 
        return 0;
@@ -1634,7 +1725,6 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
        txdr->next_to_use = 0;
        txdr->next_to_clean = 0;
        txdr->work_limit = txdr->count;
-       spin_lock_init(&txdr->tx_lock);
 
        return 0;
 }
@@ -1828,10 +1918,8 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
 
        netdev->mtu = new_mtu;
 
-       if (netif_running(netdev)) {
-               ixgbe_down(adapter);
-               ixgbe_up(adapter);
-       }
+       if (netif_running(netdev))
+               ixgbe_reinit_locked(adapter);
 
        return 0;
 }
@@ -1852,14 +1940,8 @@ static int ixgbe_open(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        int err;
-       u32 ctrl_ext;
        u32 num_rx_queues = adapter->num_rx_queues;
 
-       /* Let firmware know the driver has taken over */
-       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-                       ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
-
 try_intr_reinit:
        /* allocate transmit descriptors */
        err = ixgbe_setup_all_tx_resources(adapter);
@@ -1910,6 +1992,7 @@ try_intr_reinit:
        return 0;
 
 err_up:
+       ixgbe_release_hw_control(adapter);
        ixgbe_free_irq(adapter);
 err_req_irq:
        ixgbe_free_all_rx_resources(adapter);
@@ -1935,7 +2018,6 @@ err_setup_tx:
 static int ixgbe_close(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       u32 ctrl_ext;
 
        ixgbe_down(adapter);
        ixgbe_free_irq(adapter);
@@ -1943,9 +2025,7 @@ static int ixgbe_close(struct net_device *netdev)
        ixgbe_free_all_tx_resources(adapter);
        ixgbe_free_all_rx_resources(adapter);
 
-       ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-                       ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+       ixgbe_release_hw_control(adapter);
 
        return 0;
 }
@@ -1957,22 +2037,26 @@ static int ixgbe_close(struct net_device *netdev)
 void ixgbe_update_stats(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-       u64 good_rx, missed_rx, bprc;
+       u64 total_mpc = 0;
+       u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
 
        adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
-       good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC);
-       missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6));
-       missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7));
-       adapter->stats.gprc += (good_rx - missed_rx);
-
-       adapter->stats.mpc[0] += missed_rx;
+       for (i = 0; i < 8; i++) {
+               /* for packet buffers not used, the register should read 0 */
+               mpc = IXGBE_READ_REG(hw, IXGBE_MPC(i));
+               missed_rx += mpc;
+               adapter->stats.mpc[i] += mpc;
+               total_mpc += adapter->stats.mpc[i];
+               adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+       }
+       adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
+       /* work around hardware counting issue */
+       adapter->stats.gprc -= missed_rx;
+
+       /* 82598 hardware only has a 32 bit counter in the high register */
        adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+       adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+       adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
        bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
        adapter->stats.bprc += bprc;
        adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
@@ -1984,35 +2068,37 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
        adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
        adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
-
        adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
        adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
-       adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC);
        adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
-       adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+       lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+       adapter->stats.lxontxc += lxon;
+       lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+       adapter->stats.lxofftxc += lxoff;
        adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
        adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
-       adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
-       adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0));
+       adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+       /*
+        * 82598 errata - tx of flow control packets is included in tx counters
+        */
+       xon_off_tot = lxon + lxoff;
+       adapter->stats.gptc -= xon_off_tot;
+       adapter->stats.mptc -= xon_off_tot;
+       adapter->stats.gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN));
        adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
        adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
        adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
-       adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
        adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
        adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+       adapter->stats.ptc64 -= xon_off_tot;
        adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
        adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
        adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
        adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
        adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
-       adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
        adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
 
        /* Fill out the OS statistics structure */
-       adapter->net_stats.rx_packets = adapter->stats.gprc;
-       adapter->net_stats.tx_packets = adapter->stats.gptc;
-       adapter->net_stats.rx_bytes = adapter->stats.gorc;
-       adapter->net_stats.tx_bytes = adapter->stats.gotc;
        adapter->net_stats.multicast = adapter->stats.mprc;
 
        /* Rx Errors */
@@ -2021,8 +2107,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        adapter->net_stats.rx_dropped = 0;
        adapter->net_stats.rx_length_errors = adapter->stats.rlec;
        adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
-       adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0];
-
+       adapter->net_stats.rx_missed_errors = total_mpc;
 }
 
 /**
@@ -2076,15 +2161,6 @@ static void ixgbe_watchdog(unsigned long data)
                          round_jiffies(jiffies + 2 * HZ));
 }
 
-#define IXGBE_MAX_TXD_PWR      14
-#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
-
-/* Tx Descriptors needed, worst case */
-#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
-                        (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
-#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
-       MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1)   /* for context */
-
 static int ixgbe_tso(struct ixgbe_adapter *adapter,
                         struct ixgbe_ring *tx_ring, struct sk_buff *skb,
                         u32 tx_flags, u8 *hdr_len)
@@ -2356,6 +2432,37 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
        writel(i, adapter->hw.hw_addr + tx_ring->tail);
 }
 
+static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
+                                struct ixgbe_ring *tx_ring, int size)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       netif_stop_queue(netdev);
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it. */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available. */
+       if (likely(IXGBE_DESC_UNUSED(tx_ring) < size))
+               return -EBUSY;
+
+       /* A reprieve! - use start_queue because it doesn't call schedule */
+       netif_wake_queue(netdev);
+       ++adapter->restart_queue;
+       return 0;
+}
+
+static int ixgbe_maybe_stop_tx(struct net_device *netdev,
+                              struct ixgbe_ring *tx_ring, int size)
+{
+       if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
+               return 0;
+       return __ixgbe_maybe_stop_tx(netdev, tx_ring, size);
+}
+
+
 static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -2363,7 +2470,6 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        unsigned int len = skb->len;
        unsigned int first;
        unsigned int tx_flags = 0;
-       unsigned long flags = 0;
        u8 hdr_len;
        int tso;
        unsigned int mss = 0;
@@ -2389,14 +2495,10 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        for (f = 0; f < nr_frags; f++)
                count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
 
-       spin_lock_irqsave(&tx_ring->tx_lock, flags);
-       if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) {
+       if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) {
                adapter->tx_busy++;
-               netif_stop_queue(netdev);
-               spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
                return NETDEV_TX_BUSY;
        }
-       spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
        if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
                tx_flags |= IXGBE_TX_FLAGS_VLAN;
                tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
@@ -2423,11 +2525,7 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        netdev->trans_start = jiffies;
 
-       spin_lock_irqsave(&tx_ring->tx_lock, flags);
-       /* Make sure there is space in the ring for the next send. */
-       if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED)
-               netif_stop_queue(netdev);
-       spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+       ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
 
        return NETDEV_TX_OK;
 }
@@ -2697,6 +2795,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        return 0;
 
 err_register:
+       ixgbe_release_hw_control(adapter);
 err_hw_init:
 err_sw_init:
 err_eeprom:
@@ -2732,6 +2831,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
 
        unregister_netdev(netdev);
 
+       ixgbe_release_hw_control(adapter);
+
        kfree(adapter->tx_ring);
        kfree(adapter->rx_ring);
 
index 651c269..b528ce7 100644 (file)
@@ -1652,6 +1652,11 @@ static void eth_tx_fill_frag_descs(struct mv643xx_private *mp,
        }
 }
 
+static inline __be16 sum16_as_be(__sum16 sum)
+{
+       return (__force __be16)sum;
+}
+
 /**
  * eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw
  *
@@ -1689,7 +1694,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
        desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               BUG_ON(skb->protocol != ETH_P_IP);
+               BUG_ON(skb->protocol != htons(ETH_P_IP));
 
                cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
                           ETH_GEN_IP_V_4_CHECKSUM  |
@@ -1698,10 +1703,10 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
                switch (ip_hdr(skb)->protocol) {
                case IPPROTO_UDP:
                        cmd_sts |= ETH_UDP_FRAME;
-                       desc->l4i_chk = udp_hdr(skb)->check;
+                       desc->l4i_chk = ntohs(sum16_as_be(udp_hdr(skb)->check));
                        break;
                case IPPROTO_TCP:
-                       desc->l4i_chk = tcp_hdr(skb)->check;
+                       desc->l4i_chk = ntohs(sum16_as_be(tcp_hdr(skb)->check));
                        break;
                default:
                        BUG();
index 1b51bb6..5aa0a80 100644 (file)
@@ -2468,9 +2468,10 @@ static int __init pppol2tp_init(void)
 
 out:
        return err;
-
+#ifdef CONFIG_PROC_FS
 out_unregister_pppox_proto:
        unregister_pppox_proto(PX_PROTO_OL2TP);
+#endif
 out_unregister_pppol2tp_proto:
        proto_unregister(&pppol2tp_sk_proto);
        goto out;
index dc06236..9a62959 100644 (file)
@@ -857,7 +857,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 
        /* On chips without ram buffer, pause is controled by MAC level */
-       if (sky2_read8(hw, B2_E_0) == 0) {
+       if (!(hw->flags & SKY2_HW_RAM_BUFFER)) {
                sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
                sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
 
@@ -1194,7 +1194,7 @@ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2)
        struct sk_buff *skb;
        int i;
 
-       if (sky2->hw->flags & SKY2_HW_FIFO_HANG_CHECK) {
+       if (sky2->hw->flags & SKY2_HW_RAM_BUFFER) {
                unsigned char *start;
                /*
                 * Workaround for a bug in FIFO that cause hang
@@ -1387,6 +1387,7 @@ static int sky2_up(struct net_device *dev)
        if (ramsize > 0) {
                u32 rxspace;
 
+               hw->flags |= SKY2_HW_RAM_BUFFER;
                pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
                if (ramsize < 16)
                        rxspace = ramsize / 2;
@@ -2026,7 +2027,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
 
        synchronize_irq(hw->pdev->irq);
 
-       if (sky2_read8(hw, B2_E_0) == 0)
+       if (!(hw->flags & SKY2_HW_RAM_BUFFER))
                sky2_set_tx_stfwd(hw, port);
 
        ctl = gma_read16(hw, port, GM_GP_CTRL);
@@ -2566,7 +2567,7 @@ static void sky2_watchdog(unsigned long arg)
                        ++active;
 
                        /* For chips with Rx FIFO, check if stuck */
-                       if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) &&
+                       if ((hw->flags & SKY2_HW_RAM_BUFFER) &&
                             sky2_rx_hung(dev)) {
                                pr_info(PFX "%s: receiver hang detected\n",
                                        dev->name);
@@ -2722,11 +2723,7 @@ static int __devinit sky2_init(struct sky2_hw *hw)
 
        switch(hw->chip_id) {
        case CHIP_ID_YUKON_XL:
-               hw->flags = SKY2_HW_GIGABIT
-                       | SKY2_HW_NEWER_PHY;
-               if (hw->chip_rev < 3)
-                       hw->flags |= SKY2_HW_FIFO_HANG_CHECK;
-
+               hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
                break;
 
        case CHIP_ID_YUKON_EC_U:
@@ -2752,7 +2749,7 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                        dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
                        return -EOPNOTSUPP;
                }
-               hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK;
+               hw->flags = SKY2_HW_GIGABIT;
                break;
 
        case CHIP_ID_YUKON_FE:
index 2bced1a..5ab5c1c 100644 (file)
@@ -2045,7 +2045,7 @@ struct sky2_hw {
 #define SKY2_HW_FIBRE_PHY      0x00000002
 #define SKY2_HW_GIGABIT                0x00000004
 #define SKY2_HW_NEWER_PHY      0x00000008
-#define SKY2_HW_FIFO_HANG_CHECK        0x00000010
+#define SKY2_HW_RAM_BUFFER     0x00000010
 #define SKY2_HW_NEW_LE         0x00000020      /* new LSOv2 format */
 #define SKY2_HW_AUTO_TX_SUM    0x00000040      /* new IP decode for Tx */
 #define SKY2_HW_ADV_POWER_CTL  0x00000080      /* additional PHY power regs */
index c99ce74..3af5b92 100644 (file)
@@ -465,7 +465,7 @@ static struct pci_driver tlan_driver = {
 
 static int __init tlan_probe(void)
 {
-       static int      pad_allocated;
+       int rc = -ENODEV;
 
        printk(KERN_INFO "%s", tlan_banner);
 
@@ -473,17 +473,22 @@ static int __init tlan_probe(void)
 
        if (TLanPadBuffer == NULL) {
                printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n");
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto err_out;
        }
 
        memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE);
-       pad_allocated = 1;
 
        TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n");
 
        /* Use new style PCI probing. Now the kernel will
           do most of this for us */
-       pci_register_driver(&tlan_driver);
+       rc = pci_register_driver(&tlan_driver);
+
+       if (rc != 0) {
+               printk(KERN_ERR "TLAN: Could not register pci driver.\n");
+               goto err_out_pci_free;
+       }
 
        TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n");
        TLan_EisaProbe();
@@ -493,11 +498,17 @@ static int __init tlan_probe(void)
                 tlan_have_pci, tlan_have_eisa);
 
        if (TLanDevicesInstalled == 0) {
-               pci_unregister_driver(&tlan_driver);
-               pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
-               return -ENODEV;
+               rc = -ENODEV;
+               goto  err_out_pci_unreg;
        }
        return 0;
+
+err_out_pci_unreg:
+       pci_unregister_driver(&tlan_driver);
+err_out_pci_free:
+       pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
+err_out:
+       return rc;
 }
 
 
index 8fc7274..6b93d01 100644 (file)
@@ -441,7 +441,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&card->lock,flags);
        trigger_transmit(card);
 
-       return -EIO;
+       return NETDEV_TX_BUSY;
 }
 
 
index e3ba14a..c69e654 100644 (file)
@@ -109,7 +109,7 @@ int uec_mdio_reset(struct mii_bus *bus)
        struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
        unsigned int timeout = PHY_INIT_TIMEOUT;
 
-       spin_lock_bh(&bus->mdio_lock);
+       mutex_lock(&bus->mdio_lock);
 
        /* Reset the management interface */
        out_be32(&regs->miimcfg, MIIMCFG_RESET_MANAGEMENT);
@@ -121,7 +121,7 @@ int uec_mdio_reset(struct mii_bus *bus)
        while ((in_be32(&regs->miimind) & MIIMIND_BUSY) && timeout--)
                cpu_relax();
 
-       spin_unlock_bh(&bus->mdio_lock);
+       mutex_unlock(&bus->mdio_lock);
 
        if (timeout <= 0) {
                printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
index e66de0c..fdc2367 100644 (file)
@@ -302,10 +302,12 @@ static int virtnet_open(struct net_device *dev)
 
        /* If all buffers were filled by other side before we napi_enabled, we
         * won't get another interrupt, so process any outstanding packets
-        * now.  virtnet_poll wants re-enable the queue, so we disable here. */
-       vi->rvq->vq_ops->disable_cb(vi->rvq);
-       netif_rx_schedule(vi->dev, &vi->napi);
-
+        * now.  virtnet_poll wants re-enable the queue, so we disable here.
+        * We synchronize against interrupts via NAPI_STATE_SCHED */
+       if (netif_rx_schedule_prep(dev, &vi->napi)) {
+               vi->rvq->vq_ops->disable_cb(vi->rvq);
+               __netif_rx_schedule(dev, &vi->napi);
+       }
        return 0;
 }
 
index d553e6f..39951d0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Generic HDLC support routines for Linux
  *
- * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License
@@ -39,7 +39,7 @@
 #include <net/net_namespace.h>
 
 
-static const char* version = "HDLC support module revision 1.21";
+static const char* version = "HDLC support module revision 1.22";
 
 #undef DEBUG_LINK
 
@@ -66,19 +66,15 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
 static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
                    struct packet_type *p, struct net_device *orig_dev)
 {
-       struct hdlc_device_desc *desc = dev_to_desc(dev);
+       struct hdlc_device *hdlc = dev_to_hdlc(dev);
 
        if (dev->nd_net != &init_net) {
                kfree_skb(skb);
                return 0;
        }
 
-       if (desc->netif_rx)
-               return desc->netif_rx(skb);
-
-       desc->stats.rx_dropped++; /* Shouldn't happen */
-       dev_kfree_skb(skb);
-       return NET_RX_DROP;
+       BUG_ON(!hdlc->proto->netif_rx);
+       return hdlc->proto->netif_rx(skb);
 }
 
 
@@ -87,7 +83,7 @@ static inline void hdlc_proto_start(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
        if (hdlc->proto->start)
-               return hdlc->proto->start(dev);
+               hdlc->proto->start(dev);
 }
 
 
@@ -96,7 +92,7 @@ static inline void hdlc_proto_stop(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
        if (hdlc->proto->stop)
-               return hdlc->proto->stop(dev);
+               hdlc->proto->stop(dev);
 }
 
 
@@ -263,8 +259,7 @@ static void hdlc_setup(struct net_device *dev)
 struct net_device *alloc_hdlcdev(void *priv)
 {
        struct net_device *dev;
-       dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
-                          sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+       dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", hdlc_setup);
        if (dev)
                dev_to_hdlc(dev)->priv = priv;
        return dev;
@@ -281,7 +276,7 @@ void unregister_hdlc_device(struct net_device *dev)
 
 
 int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
-                        int (*rx)(struct sk_buff *skb), size_t size)
+                        size_t size)
 {
        detach_hdlc_protocol(dev);
 
@@ -297,7 +292,6 @@ int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
                        return -ENOBUFS;
                }
        dev_to_hdlc(dev)->proto = proto;
-       dev_to_desc(dev)->netif_rx = rx;
        return 0;
 }
 
index 038a6e7..7133c68 100644 (file)
@@ -250,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb)
        return NET_RX_DROP;
 
  rx_error:
-       dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
+       dev_to_hdlc(dev)->stats.rx_errors++; /* Mark error */
        dev_kfree_skb_any(skb);
        return NET_RX_DROP;
 }
@@ -314,6 +314,7 @@ static struct hdlc_proto proto = {
        .stop           = cisco_stop,
        .type_trans     = cisco_type_trans,
        .ioctl          = cisco_ioctl,
+       .netif_rx       = cisco_rx,
        .module         = THIS_MODULE,
 };
 
@@ -360,7 +361,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, cisco_rx,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(struct cisco_state));
                if (result)
                        return result;
index 071a64c..c4ab032 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/pkt_sched.h>
-#include <linux/random.h>
 #include <linux/inetdevice.h>
 #include <linux/lapb.h>
 #include <linux/rtnetlink.h>
@@ -136,6 +135,10 @@ typedef struct pvc_device_struct {
        }state;
 }pvc_device;
 
+struct pvc_desc {
+       struct net_device_stats stats;
+       pvc_device *pvc;
+};
 
 struct frad_state {
        fr_proto settings;
@@ -171,17 +174,20 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci)
 }
 
 
-static inline struct frad_state * state(hdlc_device *hdlc)
+static inline struct frad_state* state(hdlc_device *hdlc)
 {
        return(struct frad_state *)(hdlc->state);
 }
 
-
-static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+static inline struct pvc_desc* pvcdev_to_desc(struct net_device *dev)
 {
        return dev->priv;
 }
 
+static inline struct net_device_stats* pvc_get_stats(struct net_device *dev)
+{
+       return &pvcdev_to_desc(dev)->stats;
+}
 
 static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
 {
@@ -351,7 +357,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
 
 static int pvc_open(struct net_device *dev)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
 
        if ((pvc->frad->flags & IFF_UP) == 0)
                return -EIO;  /* Frad must be UP in order to activate PVC */
@@ -371,7 +377,7 @@ static int pvc_open(struct net_device *dev)
 
 static int pvc_close(struct net_device *dev)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
 
        if (--pvc->open_count == 0) {
                hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
@@ -390,7 +396,7 @@ static int pvc_close(struct net_device *dev)
 
 static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
        fr_proto_pvc_info info;
 
        if (ifr->ifr_settings.type == IF_GET_PROTO) {
@@ -416,17 +422,9 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EINVAL;
 }
 
-
-static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
-{
-       return &dev_to_desc(dev)->stats;
-}
-
-
-
 static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       pvc_device *pvc = dev_to_pvc(dev);
+       pvc_device *pvc = pvcdev_to_desc(dev)->pvc;
        struct net_device_stats *stats = pvc_get_stats(dev);
 
        if (pvc->state.active) {
@@ -957,7 +955,7 @@ static int fr_rx(struct sk_buff *skb)
 
 
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-               dev_to_desc(frad)->stats.rx_dropped++;
+               dev_to_hdlc(frad)->stats.rx_dropped++;
                return NET_RX_DROP;
        }
 
@@ -1018,7 +1016,7 @@ static int fr_rx(struct sk_buff *skb)
        }
 
  rx_error:
-       dev_to_desc(frad)->stats.rx_errors++; /* Mark error */
+       dev_to_hdlc(frad)->stats.rx_errors++; /* Mark error */
        dev_kfree_skb_any(skb);
        return NET_RX_DROP;
 }
@@ -1109,11 +1107,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
        used = pvc_is_used(pvc);
 
        if (type == ARPHRD_ETHER)
-               dev = alloc_netdev(sizeof(struct net_device_stats),
-                                  "pvceth%d", ether_setup);
+               dev = alloc_netdev(sizeof(struct pvc_desc), "pvceth%d",
+                                  ether_setup);
        else
-               dev = alloc_netdev(sizeof(struct net_device_stats),
-                                  "pvc%d", pvc_setup);
+               dev = alloc_netdev(sizeof(struct pvc_desc), "pvc%d", pvc_setup);
 
        if (!dev) {
                printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
@@ -1122,10 +1119,9 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
                return -ENOBUFS;
        }
 
-       if (type == ARPHRD_ETHER) {
-               memcpy(dev->dev_addr, "\x00\x01", 2);
-                get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
-       } else {
+       if (type == ARPHRD_ETHER)
+               random_ether_addr(dev->dev_addr);
+       else {
                *(__be16*)dev->dev_addr = htons(dlci);
                dlci_to_q922(dev->broadcast, dlci);
        }
@@ -1137,7 +1133,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
        dev->change_mtu = pvc_change_mtu;
        dev->mtu = HDLC_MAX_MTU;
        dev->tx_queue_len = 0;
-       dev->priv = pvc;
+       pvcdev_to_desc(dev)->pvc = pvc;
 
        result = dev_alloc_name(dev, dev->name);
        if (result < 0) {
@@ -1219,6 +1215,7 @@ static struct hdlc_proto proto = {
        .stop           = fr_stop,
        .detach         = fr_destroy,
        .ioctl          = fr_ioctl,
+       .netif_rx       = fr_rx,
        .module         = THIS_MODULE,
 };
 
@@ -1277,7 +1274,7 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
                        return result;
 
                if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */
-                       result = attach_hdlc_protocol(dev, &proto, fr_rx,
+                       result = attach_hdlc_protocol(dev, &proto,
                                                      sizeof(struct frad_state));
                        if (result)
                                return result;
index 519e155..10396d9 100644 (file)
@@ -122,7 +122,7 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, NULL,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(struct ppp_state));
                if (result)
                        return result;
index e23bc66..bbbb819 100644 (file)
@@ -82,7 +82,7 @@ static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, NULL,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(raw_hdlc_proto));
                if (result)
                        return result;
index 8895394..d20c685 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/pkt_sched.h>
-#include <linux/random.h>
 #include <linux/inetdevice.h>
 #include <linux/lapb.h>
 #include <linux/rtnetlink.h>
@@ -96,7 +95,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               result = attach_hdlc_protocol(dev, &proto, NULL,
+               result = attach_hdlc_protocol(dev, &proto,
                                              sizeof(raw_hdlc_proto));
                if (result)
                        return result;
@@ -107,8 +106,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
                ether_setup(dev);
                dev->change_mtu = old_ch_mtu;
                dev->tx_queue_len = old_qlen;
-               memcpy(dev->dev_addr, "\x00\x01", 2);
-                get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
+               random_ether_addr(dev->dev_addr);
                netif_dormant_off(dev);
                return 0;
        }
index cd7b22f..c15cc11 100644 (file)
@@ -164,17 +164,17 @@ static void x25_close(struct net_device *dev)
 
 static int x25_rx(struct sk_buff *skb)
 {
-       struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
+       struct hdlc_device *hdlc = dev_to_hdlc(skb->dev);
 
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-               desc->stats.rx_dropped++;
+               hdlc->stats.rx_dropped++;
                return NET_RX_DROP;
        }
 
        if (lapb_data_received(skb->dev, skb) == LAPB_OK)
                return NET_RX_SUCCESS;
 
-       desc->stats.rx_errors++;
+       hdlc->stats.rx_errors++;
        dev_kfree_skb_any(skb);
        return NET_RX_DROP;
 }
@@ -184,6 +184,7 @@ static struct hdlc_proto proto = {
        .open           = x25_open,
        .close          = x25_close,
        .ioctl          = x25_ioctl,
+       .netif_rx       = x25_rx,
        .module         = THIS_MODULE,
 };
 
@@ -211,8 +212,7 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
                if (result)
                        return result;
 
-               if ((result = attach_hdlc_protocol(dev, &proto,
-                                                  x25_rx, 0)) != 0)
+               if ((result = attach_hdlc_protocol(dev, &proto, 0)))
                        return result;
                dev->hard_start_xmit = x25_xmit;
                dev->type = ARPHRD_X25;
index 8a708b7..3dfb28a 100644 (file)
@@ -337,7 +337,7 @@ static inline int txring_to_priority(struct b43_dmaring *ring)
        return idx_to_prio[index];
 }
 
-u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
 {
        static const u16 map64[] = {
                B43_MMIO_DMA64_BASE0,
@@ -356,7 +356,7 @@ u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
                B43_MMIO_DMA32_BASE5,
        };
 
-       if (dma64bit) {
+       if (type == B43_DMA_64BIT) {
                B43_WARN_ON(!(controller_idx >= 0 &&
                              controller_idx < ARRAY_SIZE(map64)));
                return map64[controller_idx];
@@ -437,7 +437,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
         * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
         * which accounts for the GFP_DMA flag below.
         */
-       if (ring->dma64)
+       if (ring->type == B43_DMA_64BIT)
                flags |= GFP_DMA;
        ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
                                            &(ring->dmabase), flags);
@@ -459,7 +459,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
 }
 
 /* Reset the RX DMA channel */
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base,
+                                     enum b43_dmatype type)
 {
        int i;
        u32 value;
@@ -467,12 +468,13 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 
        might_sleep();
 
-       offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+       offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
        b43_write32(dev, mmio_base + offset, 0);
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_RXSTATUS :
+                                                  B43_DMA32_RXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_RXSTAT;
                        if (value == B43_DMA64_RXSTAT_DISABLED) {
                                i = -1;
@@ -496,7 +498,8 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 }
 
 /* Reset the TX DMA channel */
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
+                                     enum b43_dmatype type)
 {
        int i;
        u32 value;
@@ -505,9 +508,10 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
        might_sleep();
 
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+                                                  B43_DMA32_TXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_TXSTAT;
                        if (value == B43_DMA64_TXSTAT_DISABLED ||
                            value == B43_DMA64_TXSTAT_IDLEWAIT ||
@@ -522,12 +526,13 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
                }
                msleep(1);
        }
-       offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+       offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
        b43_write32(dev, mmio_base + offset, 0);
        for (i = 0; i < 10; i++) {
-               offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+               offset = (type == B43_DMA_64BIT) ? B43_DMA64_TXSTATUS :
+                                                  B43_DMA32_TXSTATUS;
                value = b43_read32(dev, mmio_base + offset);
-               if (dma64) {
+               if (type == B43_DMA_64BIT) {
                        value &= B43_DMA64_TXSTAT;
                        if (value == B43_DMA64_TXSTAT_DISABLED) {
                                i = -1;
@@ -552,6 +557,33 @@ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
        return 0;
 }
 
+/* Check if a DMA mapping address is invalid. */
+static bool b43_dma_mapping_error(struct b43_dmaring *ring,
+                                 dma_addr_t addr,
+                                 size_t buffersize)
+{
+       if (unlikely(dma_mapping_error(addr)))
+               return 1;
+
+       switch (ring->type) {
+       case B43_DMA_30BIT:
+               if ((u64)addr + buffersize > (1ULL << 30))
+                       return 1;
+               break;
+       case B43_DMA_32BIT:
+               if ((u64)addr + buffersize > (1ULL << 32))
+                       return 1;
+               break;
+       case B43_DMA_64BIT:
+               /* Currently we can't have addresses beyond
+                * 64bit in the kernel. */
+               break;
+       }
+
+       /* The address is OK. */
+       return 0;
+}
+
 static int setup_rx_descbuffer(struct b43_dmaring *ring,
                               struct b43_dmadesc_generic *desc,
                               struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
@@ -567,7 +599,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
        if (unlikely(!skb))
                return -ENOMEM;
        dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
-       if (dma_mapping_error(dmaaddr)) {
+       if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
                /* ugh. try to realloc in zone_dma */
                gfp_flags |= GFP_DMA;
 
@@ -580,7 +612,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
                                         ring->rx_buffersize, 0);
        }
 
-       if (dma_mapping_error(dmaaddr)) {
+       if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
                dev_kfree_skb_any(skb);
                return -EIO;
        }
@@ -645,7 +677,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
        u32 trans = ssb_dma_translation(ring->dev->dev);
 
        if (ring->tx) {
-               if (ring->dma64) {
+               if (ring->type == B43_DMA_64BIT) {
                        u64 ringbase = (u64) (ring->dmabase);
 
                        addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -677,7 +709,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
                err = alloc_initial_descbuffers(ring);
                if (err)
                        goto out;
-               if (ring->dma64) {
+               if (ring->type == B43_DMA_64BIT) {
                        u64 ringbase = (u64) (ring->dmabase);
 
                        addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -722,16 +754,16 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring)
 {
        if (ring->tx) {
                b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
-                                          ring->dma64);
-               if (ring->dma64) {
+                                          ring->type);
+               if (ring->type == B43_DMA_64BIT) {
                        b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
                        b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
                } else
                        b43_dma_write(ring, B43_DMA32_TXRING, 0);
        } else {
                b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
-                                          ring->dma64);
-               if (ring->dma64) {
+                                          ring->type);
+               if (ring->type == B43_DMA_64BIT) {
                        b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
                        b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
                } else
@@ -786,7 +818,8 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
 static
 struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                      int controller_index,
-                                     int for_tx, int dma64)
+                                     int for_tx,
+                                     enum b43_dmatype type)
 {
        struct b43_dmaring *ring;
        int err;
@@ -796,6 +829,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
        if (!ring)
                goto out;
+       ring->type = type;
 
        nr_slots = B43_RXRING_SLOTS;
        if (for_tx)
@@ -818,7 +852,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                          b43_txhdr_size(dev),
                                          DMA_TO_DEVICE);
 
-               if (dma_mapping_error(dma_test)) {
+               if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) {
                        /* ugh realloc */
                        kfree(ring->txhdr_cache);
                        ring->txhdr_cache = kcalloc(nr_slots,
@@ -832,7 +866,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                                  b43_txhdr_size(dev),
                                                  DMA_TO_DEVICE);
 
-                       if (dma_mapping_error(dma_test))
+                       if (b43_dma_mapping_error(ring, dma_test,
+                                                 b43_txhdr_size(dev)))
                                goto err_kfree_txhdr_cache;
                }
 
@@ -843,10 +878,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 
        ring->dev = dev;
        ring->nr_slots = nr_slots;
-       ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+       ring->mmio_base = b43_dmacontroller_base(type, controller_index);
        ring->index = controller_index;
-       ring->dma64 = !!dma64;
-       if (dma64)
+       if (type == B43_DMA_64BIT)
                ring->ops = &dma64_ops;
        else
                ring->ops = &dma32_ops;
@@ -896,8 +930,8 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
        if (!ring)
                return;
 
-       b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
-              (ring->dma64) ? "64" : "32",
+       b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
+              (unsigned int)(ring->type),
               ring->mmio_base,
               (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
        /* Device IRQs are disabled prior entering this function,
@@ -941,12 +975,22 @@ int b43_dma_init(struct b43_wldev *dev)
        struct b43_dmaring *ring;
        int err;
        u64 dmamask;
-       int dma64 = 0;
+       enum b43_dmatype type;
 
        dmamask = supported_dma_mask(dev);
-       if (dmamask == DMA_64BIT_MASK)
-               dma64 = 1;
-
+       switch (dmamask) {
+       default:
+               B43_WARN_ON(1);
+       case DMA_30BIT_MASK:
+               type = B43_DMA_30BIT;
+               break;
+       case DMA_32BIT_MASK:
+               type = B43_DMA_32BIT;
+               break;
+       case DMA_64BIT_MASK:
+               type = B43_DMA_64BIT;
+               break;
+       }
        err = ssb_dma_set_mask(dev->dev, dmamask);
        if (err) {
                b43err(dev->wl, "The machine/kernel does not support "
@@ -958,52 +1002,51 @@ int b43_dma_init(struct b43_wldev *dev)
 
        err = -ENOMEM;
        /* setup TX DMA channels. */
-       ring = b43_setup_dmaring(dev, 0, 1, dma64);
+       ring = b43_setup_dmaring(dev, 0, 1, type);
        if (!ring)
                goto out;
        dma->tx_ring0 = ring;
 
-       ring = b43_setup_dmaring(dev, 1, 1, dma64);
+       ring = b43_setup_dmaring(dev, 1, 1, type);
        if (!ring)
                goto err_destroy_tx0;
        dma->tx_ring1 = ring;
 
-       ring = b43_setup_dmaring(dev, 2, 1, dma64);
+       ring = b43_setup_dmaring(dev, 2, 1, type);
        if (!ring)
                goto err_destroy_tx1;
        dma->tx_ring2 = ring;
 
-       ring = b43_setup_dmaring(dev, 3, 1, dma64);
+       ring = b43_setup_dmaring(dev, 3, 1, type);
        if (!ring)
                goto err_destroy_tx2;
        dma->tx_ring3 = ring;
 
-       ring = b43_setup_dmaring(dev, 4, 1, dma64);
+       ring = b43_setup_dmaring(dev, 4, 1, type);
        if (!ring)
                goto err_destroy_tx3;
        dma->tx_ring4 = ring;
 
-       ring = b43_setup_dmaring(dev, 5, 1, dma64);
+       ring = b43_setup_dmaring(dev, 5, 1, type);
        if (!ring)
                goto err_destroy_tx4;
        dma->tx_ring5 = ring;
 
        /* setup RX DMA channels. */
-       ring = b43_setup_dmaring(dev, 0, 0, dma64);
+       ring = b43_setup_dmaring(dev, 0, 0, type);
        if (!ring)
                goto err_destroy_tx5;
        dma->rx_ring0 = ring;
 
        if (dev->dev->id.revision < 5) {
-               ring = b43_setup_dmaring(dev, 3, 0, dma64);
+               ring = b43_setup_dmaring(dev, 3, 0, type);
                if (!ring)
                        goto err_destroy_rx0;
                dma->rx_ring3 = ring;
        }
 
-       b43dbg(dev->wl, "%d-bit DMA initialized\n",
-              (dmamask == DMA_64BIT_MASK) ? 64 :
-              (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+       b43dbg(dev->wl, "%u-bit DMA initialized\n",
+              (unsigned int)type);
        err = 0;
       out:
        return err;
@@ -1146,7 +1189,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
                                           hdrsize, 1);
-       if (dma_mapping_error(meta_hdr->dmaaddr)) {
+       if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) {
                ring->current_slot = old_top_slot;
                ring->used_slots = old_used_slots;
                return -EIO;
@@ -1165,7 +1208,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
        /* create a bounce buffer in zone_dma on mapping failure. */
-       if (dma_mapping_error(meta->dmaaddr)) {
+       if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
                bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb) {
                        ring->current_slot = old_top_slot;
@@ -1179,7 +1222,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
                skb = bounce_skb;
                meta->skb = skb;
                meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
-               if (dma_mapping_error(meta->dmaaddr)) {
+               if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
                        ring->current_slot = old_top_slot;
                        ring->used_slots = old_used_slots;
                        err = -EIO;
index 58db03a..c0d6b69 100644 (file)
@@ -203,6 +203,12 @@ struct b43_dma_ops {
        void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
 };
 
+enum b43_dmatype {
+       B43_DMA_30BIT   = 30,
+       B43_DMA_32BIT   = 32,
+       B43_DMA_64BIT   = 64,
+};
+
 struct b43_dmaring {
        /* Lowlevel DMA ops. */
        const struct b43_dma_ops *ops;
@@ -235,8 +241,8 @@ struct b43_dmaring {
        int index;
        /* Boolean. Is this a TX ring? */
        bool tx;
-       /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
-       bool dma64;
+       /* The type of DMA engine used. */
+       enum b43_dmatype type;
        /* Boolean. Is this ring stopped at ieee80211 level? */
        bool stopped;
        /* Lock, only used for TX. */
@@ -255,8 +261,7 @@ static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
        return b43_read32(ring->dev, ring->mmio_base + offset);
 }
 
-static inline
-    void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+static inline void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
 {
        b43_write32(ring->dev, ring->mmio_base + offset, value);
 }
@@ -264,13 +269,6 @@ static inline
 int b43_dma_init(struct b43_wldev *dev);
 void b43_dma_free(struct b43_wldev *dev);
 
-int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
-                              u16 dmacontroller_mmio_base, int dma64);
-int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
-                              u16 dmacontroller_mmio_base, int dma64);
-
-u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
 void b43_dma_tx_suspend(struct b43_wldev *dev);
 void b43_dma_tx_resume(struct b43_wldev *dev);
 
index 83161d9..6e08405 100644 (file)
@@ -1164,7 +1164,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 {
        const struct b43legacy_dma_ops *ops = ring->ops;
        u8 *header;
-       int slot;
+       int slot, old_top_slot, old_used_slots;
        int err;
        struct b43legacy_dmadesc_generic *desc;
        struct b43legacy_dmadesc_meta *meta;
@@ -1174,6 +1174,9 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 #define SLOTS_PER_PACKET  2
        B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
 
+       old_top_slot = ring->current_slot;
+       old_used_slots = ring->used_slots;
+
        /* Get a slot for the header. */
        slot = request_slot(ring);
        desc = ops->idx2desc(ring, slot, &meta_hdr);
@@ -1181,9 +1184,14 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
 
        header = &(ring->txhdr_cache[slot * sizeof(
                               struct b43legacy_txhdr_fw3)]);
-       b43legacy_generate_txhdr(ring->dev, header,
+       err = b43legacy_generate_txhdr(ring->dev, header,
                                 skb->data, skb->len, ctl,
                                 generate_cookie(ring, slot));
+       if (unlikely(err)) {
+               ring->current_slot = old_top_slot;
+               ring->used_slots = old_used_slots;
+               return err;
+       }
 
        meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
                                       sizeof(struct b43legacy_txhdr_fw3), 1);
@@ -1206,6 +1214,8 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
        if (dma_mapping_error(meta->dmaaddr)) {
                bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -ENOMEM;
                        goto out_unmap_hdr;
                }
@@ -1216,6 +1226,8 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
                meta->skb = skb;
                meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
                if (dma_mapping_error(meta->dmaaddr)) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -EIO;
                        goto out_free_bounce;
                }
@@ -1282,6 +1294,13 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
        B43legacy_BUG_ON(ring->stopped);
 
        err = dma_tx_fragment(ring, skb, ctl);
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+               dev_kfree_skb_any(skb);
+               err = 0;
+               goto out_unlock;
+       }
        if (unlikely(err)) {
                b43legacyerr(dev->wl, "DMA tx mapping failure\n");
                goto out_unlock;
index aa20d5d..53f7f2e 100644 (file)
@@ -3160,8 +3160,6 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
 
        ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
-       memset(wl->bssid, 0, ETH_ALEN);
-       memset(wl->mac_addr, 0, ETH_ALEN);
        b43legacy_upload_card_macaddress(dev);
        b43legacy_security_init(dev);
        b43legacy_rng_init(wl);
@@ -3263,6 +3261,13 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
         * LEDs that are registered later depend on it. */
        b43legacy_rfkill_init(dev);
 
+       /* Kill all old instance specific information to make sure
+        * the card won't use it in the short timeframe between start
+        * and mac80211 reconfiguring it. */
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       wl->filter_flags = 0;
+
        mutex_lock(&wl->mutex);
 
        if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
index e4f4c5c..bcdd54e 100644 (file)
@@ -181,7 +181,7 @@ union txhdr_union {
        struct b43legacy_txhdr_fw3 txhdr_fw3;
 };
 
-static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
+static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
                                  struct sk_buff *skb,
                                  struct b43legacy_pio_txpacket *packet,
                                  size_t txhdr_size)
@@ -189,14 +189,17 @@ static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
        union txhdr_union txhdr_data;
        u8 *txhdr = NULL;
        unsigned int octets;
+       int err;
 
        txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
 
        B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
-       b43legacy_generate_txhdr(queue->dev,
+       err = b43legacy_generate_txhdr(queue->dev,
                                 txhdr, skb->data, skb->len,
                                 &packet->txstat.control,
                                 generate_cookie(queue, packet));
+       if (err)
+               return err;
 
        tx_start(queue);
        octets = skb->len + txhdr_size;
@@ -204,6 +207,8 @@ static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
                octets--;
        tx_data(queue, txhdr, (u8 *)skb->data, octets);
        tx_complete(queue, skb);
+
+       return 0;
 }
 
 static void free_txpacket(struct b43legacy_pio_txpacket *packet,
@@ -226,6 +231,7 @@ static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
        struct b43legacy_pioqueue *queue = packet->queue;
        struct sk_buff *skb = packet->skb;
        u16 octets;
+       int err;
 
        octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
        if (queue->tx_devq_size < octets) {
@@ -247,8 +253,14 @@ static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
        if (queue->tx_devq_used + octets > queue->tx_devq_size)
                return -EBUSY;
        /* Now poke the device. */
-       pio_tx_write_fragment(queue, skb, packet,
+       err = pio_tx_write_fragment(queue, skb, packet,
                              sizeof(struct b43legacy_txhdr_fw3));
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+               free_txpacket(packet, 1);
+               return 0;
+       }
 
        /* Account for the packet size.
         * (We must not overflow the device TX queue)
@@ -486,6 +498,9 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
        queue = parse_cookie(dev, status->cookie, &packet);
        B43legacy_WARN_ON(!queue);
 
+       if (!packet->skb)
+               return;
+
        queue->tx_devq_packets--;
        queue->tx_devq_used -= (packet->skb->len +
                                sizeof(struct b43legacy_txhdr_fw3));
index e20c552..d84408a 100644 (file)
@@ -181,7 +181,7 @@ static u8 b43legacy_calc_fallback_rate(u8 bitrate)
        return 0;
 }
 
-static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
+static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                               struct b43legacy_txhdr_fw3 *txhdr,
                               const unsigned char *fragment_data,
                               unsigned int fragment_len,
@@ -252,6 +252,13 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
                        iv_len = min((size_t)txctl->iv_len,
                                     ARRAY_SIZE(txhdr->iv));
                        memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
+               } else {
+                       /* This key is invalid. This might only happen
+                        * in a short timeframe after machine resume before
+                        * we were able to reconfigure keys.
+                        * Drop this packet completely. Do not transmit it
+                        * unencrypted to avoid leaking information. */
+                       return -ENOKEY;
                }
        }
        b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
@@ -345,16 +352,18 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
        /* Apply the bitfields */
        txhdr->mac_ctl = cpu_to_le32(mac_ctl);
        txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+
+       return 0;
 }
 
-void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
                              const struct ieee80211_tx_control *txctl,
                              u16 cookie)
 {
-       generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
+       return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
                           fragment_data, fragment_len,
                           txctl, cookie);
 }
index 8a155d0..bab4792 100644 (file)
@@ -76,7 +76,7 @@ struct b43legacy_txhdr_fw3 {
 
 
 
-void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
index f55c757..5ee1ad6 100644 (file)
@@ -4207,13 +4207,13 @@ static u8 ratio2dB[100] = {
  * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
 int iwl3945_calc_db_from_ratio(int sig_ratio)
 {
-       /* Anything above 1000:1 just report as 60 dB */
-       if (sig_ratio > 1000)
+       /* 1000:1 or higher just report as 60 dB */
+       if (sig_ratio >= 1000)
                return 60;
 
-       /* Above 100:1, divide by 10 and use table,
+       /* 100:1 or higher, divide by 10 and use table,
         *   add 20 dB to make up for divide by 10 */
-       if (sig_ratio > 100)
+       if (sig_ratio >= 100)
                return (20 + (int)ratio2dB[sig_ratio/10]);
 
        /* We shouldn't see this */
index e9743d3..238628d 100644 (file)
@@ -1540,6 +1540,38 @@ static void __devinit detect_and_report_smsc (void)
        smsc_check(0x3f0,0x44);
        smsc_check(0x370,0x44);
 }
+
+static void __devinit detect_and_report_it87(void)
+{
+       u16 dev;
+       u8 r;
+       if (verbose_probing)
+               printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
+       if (!request_region(0x2e, 1, __FUNCTION__))
+               return;
+       outb(0x87, 0x2e);
+       outb(0x01, 0x2e);
+       outb(0x55, 0x2e);
+       outb(0x55, 0x2e);
+       outb(0x20, 0x2e);
+       dev = inb(0x2f) << 8;
+       outb(0x21, 0x2e);
+       dev |= inb(0x2f);
+       if (dev == 0x8712 || dev == 0x8705 || dev == 0x8715 ||
+           dev == 0x8716 || dev == 0x8718 || dev == 0x8726) {
+               printk(KERN_INFO "IT%04X SuperIO detected.\n", dev);
+               outb(0x07, 0x2E);       /* Parallel Port */
+               outb(0x03, 0x2F);
+               outb(0xF0, 0x2E);       /* BOOT 0x80 off */
+               r = inb(0x2f);
+               outb(0xF0, 0x2E);
+               outb(r | 8, 0x2F);
+               outb(0x02, 0x2E);       /* Lock */
+               outb(0x02, 0x2F);
+
+               release_region(0x2e, 1);
+       }
+}
 #endif /* CONFIG_PARPORT_PC_SUPERIO */
 
 static int get_superio_dma (struct parport *p)
@@ -2767,6 +2799,7 @@ enum parport_pc_pci_cards {
        netmos_9755,
        netmos_9805,
        netmos_9815,
+       quatech_sppxp100,
 };
 
 
@@ -2843,6 +2876,7 @@ static struct parport_pc_pci {
         /* netmos_9755 */               { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */
        /* netmos_9805 */               { 1, { { 0, -1 }, } }, /* untested */
        /* netmos_9815 */               { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */
+       /* quatech_sppxp100 */          { 1, { { 0, 1 }, } },
 };
 
 static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2926,6 +2960,9 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
        { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
+       /* Quatech SPPXP-100 Parallel port PCI ExpressCard */
+       { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
        { 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
@@ -3159,24 +3196,25 @@ static void __init parport_pc_find_ports (int autoirq, int autodma)
        int count = 0, err;
 
 #ifdef CONFIG_PARPORT_PC_SUPERIO
-       detect_and_report_winbond ();
-       detect_and_report_smsc ();
+       detect_and_report_it87();
+       detect_and_report_winbond();
+       detect_and_report_smsc();
 #endif
 
        /* Onboard SuperIO chipsets that show themselves on the PCI bus. */
-       count += parport_pc_init_superio (autoirq, autodma);
+       count += parport_pc_init_superio(autoirq, autodma);
 
        /* PnP ports, skip detection if SuperIO already found them */
        if (!count) {
-               err = pnp_register_driver (&parport_pc_pnp_driver);
+               err = pnp_register_driver(&parport_pc_pnp_driver);
                if (!err)
                        pnp_registered_parport = 1;
        }
 
        /* ISA ports and whatever (see asm/parport.h). */
-       parport_pc_find_nonpci_ports (autoirq, autodma);
+       parport_pc_find_nonpci_ports(autoirq, autodma);
 
-       err = pci_register_driver (&parport_pc_pci_driver);
+       err = pci_register_driver(&parport_pc_pci_driver);
        if (!err)
                pci_registered_parport = 1;
 }
index bd6ad8b..e2e95b3 100644 (file)
@@ -77,7 +77,7 @@ static struct parport_pc_pci cards[] __devinitdata = {
        /* titan_110l */                { 1, { { 3, -1 }, } },
        /* titan_210l */                { 1, { { 3, -1 }, } },
        /* netmos_9xx5_combo */         { 1, { { 2, -1 }, }, netmos_parallel_init },
-       /* netmos_9855 */               { 1, { { 0, -1 }, }, netmos_parallel_init },
+       /* netmos_9855 */               { 1, { { 2, -1 }, }, netmos_parallel_init },
        /* avlab_1s1p     */            { 1, { { 1, 2}, } },
        /* avlab_1s2p     */            { 2, { { 1, 2}, { 3, 4 },} },
        /* avlab_2s1p     */            { 1, { { 2, 3}, } },
@@ -185,7 +185,7 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
                .uart_offset    = 8,
        },
        [netmos_9855] = {
-               .flags          = FL_BASE2 | FL_BASE_BARS,
+               .flags          = FL_BASE4 | FL_BASE_BARS,
                .num_ports      = 1,
                .base_baud      = 115200,
                .uart_offset    = 8,
index 91b2dc9..8ed2648 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pci.h>
 #include <linux/dmar.h>
 #include "iova.h"
+#include "intel-iommu.h"
 
 #undef PREFIX
 #define PREFIX "DMAR:"
index 4e01df9..31fa6c9 100644 (file)
@@ -1088,7 +1088,7 @@ static void dmar_init_reserved_ranges(void)
        int i;
        u64 addr, size;
 
-       init_iova_domain(&reserved_iova_list);
+       init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
 
        /* IOAPIC ranges shouldn't be accessed by DMA */
        iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
@@ -1142,7 +1142,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        int adjust_width, agaw;
        unsigned long sagaw;
 
-       init_iova_domain(&domain->iovad);
+       init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
        spin_lock_init(&domain->mapping_lock);
 
        domain_reserve_special_ranges(domain);
index 459ad1f..0e48626 100644 (file)
 
 #include <linux/types.h>
 #include <linux/msi.h>
+#include <linux/sysdev.h>
 #include "iova.h"
 #include <linux/io.h>
 
+/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K          (12)
+#define PAGE_SIZE_4K           (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K           (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr)    (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+#define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN          IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN          IOVA_PFN(DMA_64BIT_MASK)
+
 /*
  * Intel IOMMU register specification per version 1.0 public spec.
  */
index a84571c..8de7ab6 100644 (file)
@@ -9,19 +9,19 @@
 #include "iova.h"
 
 void
-init_iova_domain(struct iova_domain *iovad)
+init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
 {
        spin_lock_init(&iovad->iova_alloc_lock);
        spin_lock_init(&iovad->iova_rbtree_lock);
        iovad->rbroot = RB_ROOT;
        iovad->cached32_node = NULL;
-
+       iovad->dma_32bit_pfn = pfn_32bit;
 }
 
 static struct rb_node *
 __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
 {
-       if ((*limit_pfn != DMA_32BIT_PFN) ||
+       if ((*limit_pfn != iovad->dma_32bit_pfn) ||
                (iovad->cached32_node == NULL))
                return rb_last(&iovad->rbroot);
        else {
@@ -37,7 +37,7 @@ static void
 __cached_rbnode_insert_update(struct iova_domain *iovad,
        unsigned long limit_pfn, struct iova *new)
 {
-       if (limit_pfn != DMA_32BIT_PFN)
+       if (limit_pfn != iovad->dma_32bit_pfn)
                return;
        iovad->cached32_node = &new->node;
 }
index ae3028d..d521b5b 100644 (file)
 #include <linux/rbtree.h>
 #include <linux/dma-mapping.h>
 
-/*
- * We need a fixed PAGE_SIZE of 4K irrespective of
- * arch PAGE_SIZE for IOMMU page tables.
- */
-#define PAGE_SHIFT_4K          (12)
-#define PAGE_SIZE_4K           (1UL << PAGE_SHIFT_4K)
-#define PAGE_MASK_4K           (((u64)-1) << PAGE_SHIFT_4K)
-#define PAGE_ALIGN_4K(addr)    (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
-
 /* IO virtual address start page frame number */
 #define IOVA_START_PFN         (1)
 
-#define IOVA_PFN(addr)         ((addr) >> PAGE_SHIFT_4K)
-#define DMA_32BIT_PFN  IOVA_PFN(DMA_32BIT_MASK)
-#define DMA_64BIT_PFN  IOVA_PFN(DMA_64BIT_MASK)
-
 /* iova structure */
 struct iova {
        struct rb_node  node;
@@ -44,6 +31,7 @@ struct iova_domain {
        spinlock_t      iova_rbtree_lock; /* Lock to protect update of rbtree */
        struct rb_root  rbroot;         /* iova domain rbtree root */
        struct rb_node  *cached32_node; /* Save last alloced node */
+       unsigned long   dma_32bit_pfn;
 };
 
 struct iova *alloc_iova_mem(void);
@@ -56,7 +44,7 @@ struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
 struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
        unsigned long pfn_hi);
 void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
-void init_iova_domain(struct iova_domain *iovad);
+void init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit);
 struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
 void put_iova_domain(struct iova_domain *iovad);
 
index a262762..12a1645 100644 (file)
@@ -161,8 +161,7 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
                        return error;
        }
 
-       if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) &&
-           pnp_can_disable(pnp_dev)) {
+       if (pnp_can_disable(pnp_dev)) {
                error = pnp_stop_dev(pnp_dev);
                if (error)
                        return error;
@@ -185,14 +184,17 @@ static int pnp_bus_resume(struct device *dev)
        if (pnp_dev->protocol && pnp_dev->protocol->resume)
                pnp_dev->protocol->resume(pnp_dev);
 
-       if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
+       if (pnp_can_write(pnp_dev)) {
                error = pnp_start_dev(pnp_dev);
                if (error)
                        return error;
        }
 
-       if (pnp_drv->resume)
-               return pnp_drv->resume(pnp_dev);
+       if (pnp_drv->resume) {
+               error = pnp_drv->resume(pnp_dev);
+               if (error)
+                       return error;
+       }
 
        return 0;
 }
index 3154804..9826584 100644 (file)
 #include <linux/errno.h>
 #include <linux/list.h>
 #include <linux/types.h>
+#include <linux/pnp.h>
 #include <linux/stat.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <asm/uaccess.h>
 
 #include "base.h"
@@ -315,8 +318,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
        return ret;
 }
 
-extern struct semaphore pnp_res_mutex;
-
 static ssize_t
 pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                          const char *ubuf, size_t count)
@@ -361,10 +362,10 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                goto done;
        }
        if (!strnicmp(buf, "get", 3)) {
-               down(&pnp_res_mutex);
+               mutex_lock(&pnp_res_mutex);
                if (pnp_can_read(dev))
                        dev->protocol->get(dev, &dev->res);
-               up(&pnp_res_mutex);
+               mutex_unlock(&pnp_res_mutex);
                goto done;
        }
        if (!strnicmp(buf, "set", 3)) {
@@ -373,7 +374,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                        goto done;
                buf += 3;
                pnp_init_resource_table(&dev->res);
-               down(&pnp_res_mutex);
+               mutex_lock(&pnp_res_mutex);
                while (1) {
                        while (isspace(*buf))
                                ++buf;
@@ -455,7 +456,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
                        }
                        break;
                }
-               up(&pnp_res_mutex);
+               mutex_unlock(&pnp_res_mutex);
                goto done;
        }
 
index c6b3d4e..c28caf2 100644 (file)
 #include <linux/pnp.h>
 #include <linux/slab.h>
 #include <linux/bitmap.h>
+#include <linux/mutex.h>
 #include "base.h"
 
-DECLARE_MUTEX(pnp_res_mutex);
+DEFINE_MUTEX(pnp_res_mutex);
 
 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 {
@@ -297,7 +298,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
        if (!pnp_can_configure(dev))
                return -ENODEV;
 
-       down(&pnp_res_mutex);
+       mutex_lock(&pnp_res_mutex);
        pnp_clean_resource_table(&dev->res);    /* start with a fresh slate */
        if (dev->independent) {
                port = dev->independent->port;
@@ -366,12 +367,12 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
        } else if (dev->dependent)
                goto fail;
 
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
        return 1;
 
 fail:
        pnp_clean_resource_table(&dev->res);
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
        return 0;
 }
 
@@ -396,7 +397,7 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
                return -ENOMEM;
        *bak = dev->res;
 
-       down(&pnp_res_mutex);
+       mutex_lock(&pnp_res_mutex);
        dev->res = *res;
        if (!(mode & PNP_CONFIG_FORCE)) {
                for (i = 0; i < PNP_MAX_PORT; i++) {
@@ -416,14 +417,14 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
                                goto fail;
                }
        }
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
 
        kfree(bak);
        return 0;
 
 fail:
        dev->res = *bak;
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
        kfree(bak);
        return -EINVAL;
 }
@@ -513,7 +514,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
        int error;
 
        if (dev->active)
-               return 0;       /* the device is already active */
+               return 0;
 
        /* ensure resources are allocated */
        if (pnp_auto_config_dev(dev))
@@ -524,7 +525,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
                return error;
 
        dev->active = 1;
-       return 1;
+       return 0;
 }
 
 /**
@@ -538,7 +539,7 @@ int pnp_disable_dev(struct pnp_dev *dev)
        int error;
 
        if (!dev->active)
-               return 0;       /* the device is already disabled */
+               return 0;
 
        error = pnp_stop_dev(dev);
        if (error)
@@ -547,11 +548,11 @@ int pnp_disable_dev(struct pnp_dev *dev)
        dev->active = 0;
 
        /* release the resources so that other devices can use them */
-       down(&pnp_res_mutex);
+       mutex_lock(&pnp_res_mutex);
        pnp_clean_resource_table(&dev->res);
-       up(&pnp_res_mutex);
+       mutex_unlock(&pnp_res_mutex);
 
-       return 1;
+       return 0;
 }
 
 /**
index 6b9840c..6aa231e 100644 (file)
@@ -391,8 +391,8 @@ acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
                                   pnpacpi_allocated_resource, res);
 }
 
-static void pnpacpi_parse_dma_option(struct pnp_option *option,
-                                    struct acpi_resource_dma *p)
+static __init void pnpacpi_parse_dma_option(struct pnp_option *option,
+                                           struct acpi_resource_dma *p)
 {
        int i;
        struct pnp_dma *dma;
@@ -411,8 +411,8 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option,
        pnp_register_dma_resource(option, dma);
 }
 
-static void pnpacpi_parse_irq_option(struct pnp_option *option,
-                                    struct acpi_resource_irq *p)
+static __init void pnpacpi_parse_irq_option(struct pnp_option *option,
+                                           struct acpi_resource_irq *p)
 {
        int i;
        struct pnp_irq *irq;
@@ -431,8 +431,8 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option,
        pnp_register_irq_resource(option, irq);
 }
 
-static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
-                                        struct acpi_resource_extended_irq *p)
+static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
+                                       struct acpi_resource_extended_irq *p)
 {
        int i;
        struct pnp_irq *irq;
@@ -451,8 +451,8 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
        pnp_register_irq_resource(option, irq);
 }
 
-static void pnpacpi_parse_port_option(struct pnp_option *option,
-                                     struct acpi_resource_io *io)
+static __init void pnpacpi_parse_port_option(struct pnp_option *option,
+                                            struct acpi_resource_io *io)
 {
        struct pnp_port *port;
 
@@ -470,8 +470,8 @@ static void pnpacpi_parse_port_option(struct pnp_option *option,
        pnp_register_port_resource(option, port);
 }
 
-static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
-                                           struct acpi_resource_fixed_io *io)
+static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+                                       struct acpi_resource_fixed_io *io)
 {
        struct pnp_port *port;
 
@@ -487,8 +487,8 @@ static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
        pnp_register_port_resource(option, port);
 }
 
-static void pnpacpi_parse_mem24_option(struct pnp_option *option,
-                                      struct acpi_resource_memory24 *p)
+static __init void pnpacpi_parse_mem24_option(struct pnp_option *option,
+                                             struct acpi_resource_memory24 *p)
 {
        struct pnp_mem *mem;
 
@@ -508,8 +508,8 @@ static void pnpacpi_parse_mem24_option(struct pnp_option *option,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpacpi_parse_mem32_option(struct pnp_option *option,
-                                      struct acpi_resource_memory32 *p)
+static __init void pnpacpi_parse_mem32_option(struct pnp_option *option,
+                                             struct acpi_resource_memory32 *p)
 {
        struct pnp_mem *mem;
 
@@ -529,8 +529,8 @@ static void pnpacpi_parse_mem32_option(struct pnp_option *option,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
-                                        struct acpi_resource_fixed_memory32 *p)
+static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+                                       struct acpi_resource_fixed_memory32 *p)
 {
        struct pnp_mem *mem;
 
@@ -549,8 +549,8 @@ static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpacpi_parse_address_option(struct pnp_option *option,
-                                        struct acpi_resource *r)
+static __init void pnpacpi_parse_address_option(struct pnp_option *option,
+                                               struct acpi_resource *r)
 {
        struct acpi_resource_address64 addr, *p = &addr;
        acpi_status status;
@@ -596,8 +596,8 @@ struct acpipnp_parse_option_s {
        struct pnp_dev *dev;
 };
 
-static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
-                                          void *data)
+static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
+                                                 void *data)
 {
        int priority = 0;
        struct acpipnp_parse_option_s *parse_data = data;
@@ -696,8 +696,8 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
        return AE_OK;
 }
 
-acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
-                                              struct pnp_dev * dev)
+acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle,
+                                                     struct pnp_dev *dev)
 {
        acpi_status status;
        struct acpipnp_parse_option_s parse_data;
index e33e03f..f7e6719 100644 (file)
@@ -315,7 +315,7 @@ struct pnp_protocol pnpbios_protocol = {
        .disable = pnpbios_disable_resources,
 };
 
-static int insert_device(struct pnp_bios_node *node)
+static int __init insert_device(struct pnp_bios_node *node)
 {
        struct list_head *pos;
        struct pnp_dev *dev;
index 3fabf11..caade35 100644 (file)
@@ -262,8 +262,8 @@ len_err:
  * Resource Configuration Options
  */
 
-static void pnpbios_parse_mem_option(unsigned char *p, int size,
-                                    struct pnp_option *option)
+static __init void pnpbios_parse_mem_option(unsigned char *p, int size,
+                                           struct pnp_option *option)
 {
        struct pnp_mem *mem;
 
@@ -278,8 +278,8 @@ static void pnpbios_parse_mem_option(unsigned char *p, int size,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpbios_parse_mem32_option(unsigned char *p, int size,
-                                      struct pnp_option *option)
+static __init void pnpbios_parse_mem32_option(unsigned char *p, int size,
+                                             struct pnp_option *option)
 {
        struct pnp_mem *mem;
 
@@ -294,8 +294,8 @@ static void pnpbios_parse_mem32_option(unsigned char *p, int size,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
-                                            struct pnp_option *option)
+static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+                                                   struct pnp_option *option)
 {
        struct pnp_mem *mem;
 
@@ -309,7 +309,7 @@ static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
        pnp_register_mem_resource(option, mem);
 }
 
-static void pnpbios_parse_irq_option(unsigned char *p, int size,
+static __init void pnpbios_parse_irq_option(unsigned char *p, int size,
                                     struct pnp_option *option)
 {
        struct pnp_irq *irq;
@@ -327,7 +327,7 @@ static void pnpbios_parse_irq_option(unsigned char *p, int size,
        pnp_register_irq_resource(option, irq);
 }
 
-static void pnpbios_parse_dma_option(unsigned char *p, int size,
+static __init void pnpbios_parse_dma_option(unsigned char *p, int size,
                                     struct pnp_option *option)
 {
        struct pnp_dma *dma;
@@ -340,8 +340,8 @@ static void pnpbios_parse_dma_option(unsigned char *p, int size,
        pnp_register_dma_resource(option, dma);
 }
 
-static void pnpbios_parse_port_option(unsigned char *p, int size,
-                                     struct pnp_option *option)
+static __init void pnpbios_parse_port_option(unsigned char *p, int size,
+                                            struct pnp_option *option)
 {
        struct pnp_port *port;
 
@@ -356,8 +356,8 @@ static void pnpbios_parse_port_option(unsigned char *p, int size,
        pnp_register_port_resource(option, port);
 }
 
-static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
-                                           struct pnp_option *option)
+static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+                                                  struct pnp_option *option)
 {
        struct pnp_port *port;
 
@@ -371,9 +371,9 @@ static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
        pnp_register_port_resource(option, port);
 }
 
-static unsigned char *pnpbios_parse_resource_option_data(unsigned char *p,
-                                                        unsigned char *end,
-                                                        struct pnp_dev *dev)
+static __init unsigned char *
+pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end,
+                                       struct pnp_dev *dev)
 {
        unsigned int len, tag;
        int priority = 0;
@@ -781,7 +781,8 @@ len_err:
  * Core Parsing Functions
  */
 
-int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node *node)
+int __init pnpbios_parse_data_stream(struct pnp_dev *dev,
+                                       struct pnp_bios_node *node)
 {
        unsigned char *p = (char *)node->data;
        unsigned char *end = (char *)(node->data + node->size);
index e903b8c..4065139 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/pnp.h>
 #include <linux/io.h>
+#include <linux/dmi.h>
 #include <linux/kallsyms.h>
 #include "base.h"
 
@@ -108,6 +109,46 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
                       "pnp: SB audio device quirk - increasing port range\n");
 }
 
+static void quirk_supermicro_h8dce_system(struct pnp_dev *dev)
+{
+       int i;
+       static struct dmi_system_id supermicro_h8dce[] = {
+               {
+                       .ident = "Supermicro H8DCE",
+                       .matches = {
+                               DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+                               DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"),
+                       },
+               },
+               { }
+       };
+
+       if (!dmi_check_system(supermicro_h8dce))
+               return;
+
+       /*
+        * On the Supermicro H8DCE, there's a system device with resources
+        * that overlap BAR 6 of the built-in SATA PCI adapter.  If the PNP
+        * system device claims them, the sata_nv driver won't be able to.
+        * More details at:
+        *     https://bugzilla.redhat.com/show_bug.cgi?id=280641
+        *     https://bugzilla.redhat.com/show_bug.cgi?id=313491
+        *     http://lkml.org/lkml/2008/1/9/449
+        *     http://thread.gmane.org/gmane.linux.acpi.devel/27312
+        */
+       for (i = 0; i < PNP_MAX_MEM; i++) {
+               if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) &&
+                   (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) {
+                       dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent"
+                               " conflict with sata_nv PCI device\n",
+                               (unsigned long long) pnp_mem_start(dev, i),
+                               (unsigned long long) (pnp_mem_start(dev, i) +
+                                       pnp_mem_len(dev, i) - 1));
+                       pnp_mem_flags(dev, i) = 0;
+               }
+       }
+}
+
 /*
  *  PnP Quirks
  *  Cards or devices that need some tweaking due to incomplete resource info
@@ -128,6 +169,8 @@ static struct pnp_fixup pnp_fixups[] = {
        {"CTL0043", quirk_sb16audio_resources},
        {"CTL0044", quirk_sb16audio_resources},
        {"CTL0045", quirk_sb16audio_resources},
+       {"PNP0c01", quirk_supermicro_h8dce_system},
+       {"PNP0c02", quirk_supermicro_h8dce_system},
        {""}
 };
 
index 87b3493..6f2f90e 100644 (file)
@@ -78,23 +78,21 @@ static const struct avset_video_mode {
        u32 aspect;
        u32 x;
        u32 y;
-       u32 interlace;
-       u32 freq;
 } video_mode_table[] = {
        {     0, }, /* auto */
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I,       A_N,  720,  480, 1, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P,       A_N,  720,  480, 0, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_N, 1280,  720, 0, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I,       A_N,  720,  576, 1, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P,       A_N,  720,  576, 0, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_N, 1280,  720, 0, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50},
-       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA,       A_W, 1280,  768, 0, 60},
-       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA,       A_N, 1280, 1024, 0, 60},
-       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA,      A_W, 1920, 1200, 0, 60},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I,       A_N,  720,  480},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P,       A_N,  720,  480},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I,       A_N,  720,  576},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P,       A_N,  720,  576},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
+       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA,       A_W, 1280,  768},
+       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA,       A_N, 1280, 1024},
+       {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA,      A_W, 1920, 1200},
 };
 
 /* supported CIDs */
@@ -544,7 +542,7 @@ static void ps3av_set_videomode_packet(u32 id)
 
 static void ps3av_set_videomode_cont(u32 id, u32 old_id)
 {
-       static int vesa = 0;
+       static int vesa;
        int res;
 
        /* video signal off */
@@ -554,9 +552,9 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
         * AV backend needs non-VESA mode setting at least one time
         * when VESA mode is used.
         */
-       if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) {
+       if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) {
                /* vesa mode */
-               ps3av_set_videomode_packet(2);  /* 480P */
+               ps3av_set_videomode_packet(PS3AV_MODE_480P);
        }
        vesa = 1;
 
@@ -596,20 +594,21 @@ static const struct {
        unsigned mask : 19;
        unsigned id :  4;
 } ps3av_preferred_modes[] = {
-       { .mask = PS3AV_RESBIT_WUXGA            << SHIFT_VESA,  .id = 13 },
-       { .mask = PS3AV_RESBIT_1920x1080P       << SHIFT_60,    .id = 5 },
-       { .mask = PS3AV_RESBIT_1920x1080P       << SHIFT_50,    .id = 10 },
-       { .mask = PS3AV_RESBIT_1920x1080I       << SHIFT_60,    .id = 4 },
-       { .mask = PS3AV_RESBIT_1920x1080I       << SHIFT_50,    .id = 9 },
-       { .mask = PS3AV_RESBIT_SXGA             << SHIFT_VESA,  .id = 12 },
-       { .mask = PS3AV_RESBIT_WXGA             << SHIFT_VESA,  .id = 11 },
-       { .mask = PS3AV_RESBIT_1280x720P        << SHIFT_60,    .id = 3 },
-       { .mask = PS3AV_RESBIT_1280x720P        << SHIFT_50,    .id = 8 },
-       { .mask = PS3AV_RESBIT_720x480P         << SHIFT_60,    .id = 2 },
-       { .mask = PS3AV_RESBIT_720x576P         << SHIFT_50,    .id = 7 },
+       { PS3AV_RESBIT_WUXGA      << SHIFT_VESA, PS3AV_MODE_WUXGA   },
+       { PS3AV_RESBIT_1920x1080P << SHIFT_60,   PS3AV_MODE_1080P60 },
+       { PS3AV_RESBIT_1920x1080P << SHIFT_50,   PS3AV_MODE_1080P50 },
+       { PS3AV_RESBIT_1920x1080I << SHIFT_60,   PS3AV_MODE_1080I60 },
+       { PS3AV_RESBIT_1920x1080I << SHIFT_50,   PS3AV_MODE_1080I50 },
+       { PS3AV_RESBIT_SXGA       << SHIFT_VESA, PS3AV_MODE_SXGA    },
+       { PS3AV_RESBIT_WXGA       << SHIFT_VESA, PS3AV_MODE_WXGA    },
+       { PS3AV_RESBIT_1280x720P  << SHIFT_60,   PS3AV_MODE_720P60  },
+       { PS3AV_RESBIT_1280x720P  << SHIFT_50,   PS3AV_MODE_720P50  },
+       { PS3AV_RESBIT_720x480P   << SHIFT_60,   PS3AV_MODE_480P    },
+       { PS3AV_RESBIT_720x576P   << SHIFT_50,   PS3AV_MODE_576P    },
 };
 
-static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
+static enum ps3av_mode_num ps3av_resbit2id(u32 res_50, u32 res_60,
+                                          u32 res_vesa)
 {
        unsigned int i;
        u32 res_all;
@@ -638,9 +637,9 @@ static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
        return 0;
 }
 
-static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
+static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
 {
-       int id;
+       enum ps3av_mode_num id;
 
        if (safe_mode)
                return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
@@ -854,7 +853,7 @@ int ps3av_set_video_mode(u32 id)
 
        /* auto mode */
        option = id & ~PS3AV_MODE_MASK;
-       if ((id & PS3AV_MODE_MASK) == 0) {
+       if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) {
                id = ps3av_auto_videomode(&ps3av->av_hw_conf);
                if (id < 1) {
                        printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
@@ -889,36 +888,6 @@ int ps3av_get_mode(void)
 
 EXPORT_SYMBOL_GPL(ps3av_get_mode);
 
-int ps3av_get_scanmode(int id)
-{
-       int size;
-
-       id = id & PS3AV_MODE_MASK;
-       size = ARRAY_SIZE(video_mode_table);
-       if (id > size - 1 || id < 0) {
-               printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
-               return -EINVAL;
-       }
-       return video_mode_table[id].interlace;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_scanmode);
-
-int ps3av_get_refresh_rate(int id)
-{
-       int size;
-
-       id = id & PS3AV_MODE_MASK;
-       size = ARRAY_SIZE(video_mode_table);
-       if (id > size - 1 || id < 0) {
-               printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
-               return -EINVAL;
-       }
-       return video_mode_table[id].freq;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate);
-
 /* get resolution by video_mode */
 int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
 {
@@ -990,7 +959,7 @@ static int ps3av_probe(struct ps3_system_bus_device *dev)
                return -ENOMEM;
 
        mutex_init(&ps3av->mutex);
-       ps3av->ps3av_mode = 0;
+       ps3av->ps3av_mode = PS3AV_MODE_AUTO;
        ps3av->dev = dev;
 
        INIT_WORK(&ps3av->work, ps3avd);
index 45e4b96..6402d69 100644 (file)
@@ -20,6 +20,10 @@ menuconfig RTC_CLASS
 
 if RTC_CLASS
 
+if GEN_RTC || RTC
+comment "Conflicting RTC option has been selected, check GEN_RTC and RTC"
+endif
+
 config RTC_HCTOSYS
        bool "Set system time from RTC on startup and resume"
        depends on RTC_CLASS = y
@@ -49,7 +53,7 @@ config RTC_HCTOSYS_DEVICE
 
          If the clock you specify here is not battery backed, it may still
          be useful to reinitialize system time when resuming from system
-         sleep states.  Do not specify an RTC here unless it stays powered
+         sleep states. Do not specify an RTC here unless it stays powered
          during all this system's supported sleep states.
 
 config RTC_DEBUG
@@ -142,7 +146,7 @@ config RTC_DRV_DS1307
          will be called rtc-ds1307.
 
 config RTC_DRV_DS1374
-       tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+       tristate "Dallas/Maxim DS1374"
        depends on RTC_CLASS && I2C
        help
          If you say yes here you get support for Dallas Semiconductor
@@ -162,7 +166,7 @@ config RTC_DRV_DS1672
          will be called rtc-ds1672.
 
 config RTC_DRV_MAX6900
-       tristate "Maxim 6900"
+       tristate "Maxim MAX6900"
        help
          If you say yes here you will get support for the
          Maxim MAX6900 I2C RTC chip.
@@ -180,10 +184,10 @@ config RTC_DRV_RS5C372
          will be called rtc-rs5c372.
 
 config RTC_DRV_ISL1208
-       tristate "Intersil 1208"
+       tristate "Intersil ISL1208"
        help
          If you say yes here you get support for the
-         Intersil 1208 RTC chip.
+         Intersil ISL1208 RTC chip.
 
          This driver can also be built as a module. If so, the module
          will be called rtc-isl1208.
@@ -220,7 +224,7 @@ config RTC_DRV_PCF8583
          will be called rtc-pcf8583.
 
 config RTC_DRV_M41T80
-       tristate "ST M41T80 series RTC"
+       tristate "ST M41T80/81/82/83/84/85/87"
        help
          If you say Y here you will get support for the
          ST M41T80 RTC chips series. Currently following chips are
@@ -252,23 +256,32 @@ comment "SPI RTC drivers"
 
 if SPI_MASTER
 
-config RTC_DRV_RS5C348
-       tristate "Ricoh RS5C348A/B"
+config RTC_DRV_MAX6902
+       tristate "Maxim MAX6902"
        help
-         If you say yes here you get support for the
-         Ricoh RS5C348A and RS5C348B RTC chips.
+         If you say yes here you will get support for the
+         Maxim MAX6902 SPI RTC chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-rs5c348.
+         will be called rtc-max6902.
 
-config RTC_DRV_MAX6902
-       tristate "Maxim 6902"
+config RTC_DRV_R9701
+       tristate "Epson RTC-9701JE"
        help
          If you say yes here you will get support for the
-         Maxim MAX6902 SPI RTC chip.
+         Epson RTC-9701JE SPI RTC chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-max6902.
+         will be called rtc-r9701.
+
+config RTC_DRV_RS5C348
+       tristate "Ricoh RS5C348A/B"
+       help
+         If you say yes here you get support for the
+         Ricoh RS5C348A and RS5C348B RTC chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-rs5c348.
 
 endif # SPI_MASTER
 
@@ -302,34 +315,50 @@ config RTC_DRV_DS1216
        help
          If you say yes here you get support for the Dallas DS1216 RTC chips.
 
-config RTC_DRV_DS1553
-       tristate "Dallas DS1553"
+config RTC_DRV_DS1302
+       tristate "Dallas DS1302"
+       depends on SH_SECUREEDGE5410
+       help
+         If you say yes here you get support for the Dallas DS1302 RTC chips.
+
+config RTC_DRV_DS1511
+       tristate "Dallas DS1511"
+       depends on RTC_CLASS
        help
          If you say yes here you get support for the
-         Dallas DS1553 timekeeping chip.
+         Dallas DS1511 timekeeping/watchdog chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-ds1553.
+         will be called rtc-ds1511.
 
-config RTC_DRV_STK17TA8
-       tristate "Simtek STK17TA8"
-       depends on RTC_CLASS
+config RTC_DRV_DS1553
+       tristate "Maxim/Dallas DS1553"
        help
          If you say yes here you get support for the
-         Simtek STK17TA8 timekeeping chip.
+         Maxim/Dallas DS1553 timekeeping chip.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-stk17ta8.
+         will be called rtc-ds1553.
 
 config RTC_DRV_DS1742
-       tristate "Dallas DS1742/1743"
+       tristate "Maxim/Dallas DS1742/1743"
        help
          If you say yes here you get support for the
-         Dallas DS1742/1743 timekeeping chip.
+         Maxim/Dallas DS1742/1743 timekeeping chip.
 
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1742.
 
+config RTC_DRV_STK17TA8
+       tristate "Simtek STK17TA8"
+       depends on RTC_CLASS
+       help
+         If you say yes here you get support for the
+         Simtek STK17TA8 timekeeping chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-stk17ta8.
+
 config RTC_DRV_M48T86
        tristate "ST M48T86/Dallas DS12887"
        help
@@ -440,10 +469,47 @@ config RTC_DRV_AT32AP700X
          AT32AP700x family processors.
 
 config RTC_DRV_AT91RM9200
-       tristate "AT91RM9200"
-       depends on ARCH_AT91RM9200
-       help
-         Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+       tristate "AT91RM9200 or AT91SAM9RL"
+       depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL
+       help
+         Driver for the internal RTC (Realtime Clock) module found on
+         Atmel AT91RM9200's and AT91SAM9RL chips.  On SAM9RL chips
+         this is powered by the backup power supply.
+
+config RTC_DRV_AT91SAM9
+       tristate "AT91SAM9x"
+       depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
+       help
+         RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer).
+         These timers are powered by the backup power supply (such as a
+         small coin cell battery), but do not need to be used as RTCs.
+
+         (On AT91SAM9rl chips you probably want to use the dedicated RTC
+         module and leave the RTT available for other uses.)
+
+config RTC_DRV_AT91SAM9_RTT
+       int
+       range 0 1
+       default 0
+       prompt "RTT module Number" if ARCH_AT91SAM9263
+       depends on RTC_DRV_AT91SAM9
+       help
+         More than one RTT module is available.  You can choose which
+         one will be used as an RTC.  The default of zero is normally
+         OK to use, though some systems use that for non-RTC purposes.
+
+config RTC_DRV_AT91SAM9_GPBR
+       int
+       range 0 3 if !ARCH_AT91SAM9263
+       range 0 15 if ARCH_AT91SAM9263
+       default 0
+       prompt "Backup Register Number"
+       depends on RTC_DRV_AT91SAM9
+       help
+         The RTC driver needs to use one of the General Purpose Backup
+         Registers (GPBRs) as well as the RTT.  You can choose which one
+         will be used.  The default of zero is normally OK to use, but
+         on some systems other software needs to use that register.
 
 config RTC_DRV_BFIN
        tristate "Blackfin On-Chip RTC"
index 465db4d..ec703f3 100644 (file)
@@ -19,11 +19,14 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
 obj-$(CONFIG_RTC_DRV_BFIN)     += rtc-bfin.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_DS1216)   += rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_DS1302)   += rtc-ds1302.o
 obj-$(CONFIG_RTC_DRV_DS1307)   += rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1374)   += rtc-ds1374.o
+obj-$(CONFIG_RTC_DRV_DS1511)   += rtc-ds1511.o
 obj-$(CONFIG_RTC_DRV_DS1553)   += rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)   += rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)   += rtc-ds1742.o
@@ -38,6 +41,7 @@ obj-$(CONFIG_RTC_DRV_OMAP)    += rtc-omap.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_PL031)    += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
 obj-$(CONFIG_RTC_DRV_RS5C313)  += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
new file mode 100644 (file)
index 0000000..bbf10ec
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * "RTT as Real Time Clock" driver for AT91SAM9 SoC family
+ *
+ * (C) 2007 Michel Benoit
+ *
+ * Based on rtc-at91rm9200.c by Rick Bronson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+
+#include <asm/mach/time.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91_rtt.h>
+
+
+/*
+ * This driver uses two configurable hardware resources that live in the
+ * AT91SAM9 backup power domain (intended to be powered at all times)
+ * to implement the Real Time Clock interfaces
+ *
+ *  - A "Real-time Timer" (RTT) counts up in seconds from a base time.
+ *    We can't assign the counter value (CRTV) ... but we can reset it.
+ *
+ *  - One of the "General Purpose Backup Registers" (GPBRs) holds the
+ *    base time, normally an offset from the beginning of the POSIX
+ *    epoch (1970-Jan-1 00:00:00 UTC).  Some systems also include the
+ *    local timezone's offset.
+ *
+ * The RTC's value is the RTT counter plus that offset.  The RTC's alarm
+ * is likewise a base (ALMV) plus that offset.
+ *
+ * Not all RTTs will be used as RTCs; some systems have multiple RTTs to
+ * choose from, or a "real" RTC module.  All systems have multiple GPBR
+ * registers available, likewise usable for more than "RTC" support.
+ */
+
+/*
+ * We store ALARM_DISABLED in ALMV to record that no alarm is set.
+ * It's also the reset value for that field.
+ */
+#define ALARM_DISABLED ((u32)~0)
+
+
+struct sam9_rtc {
+       void __iomem            *rtt;
+       struct rtc_device       *rtcdev;
+       u32                     imr;
+};
+
+#define rtt_readl(rtc, field) \
+       __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
+#define rtt_writel(rtc, field, val) \
+       __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+
+#define gpbr_readl(rtc) \
+       at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
+#define gpbr_writel(rtc, val) \
+       at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       u32 secs, secs2;
+       u32 offset;
+
+       /* read current time offset */
+       offset = gpbr_readl(rtc);
+       if (offset == 0)
+               return -EILSEQ;
+
+       /* reread the counter to help sync the two clock domains */
+       secs = rtt_readl(rtc, VR);
+       secs2 = rtt_readl(rtc, VR);
+       if (secs != secs2)
+               secs = rtt_readl(rtc, VR);
+
+       rtc_time_to_tm(offset + secs, tm);
+
+       dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime",
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       int err;
+       u32 offset, alarm, mr;
+       unsigned long secs;
+
+       dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime",
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err != 0)
+               return err;
+
+       mr = rtt_readl(rtc, MR);
+
+       /* disable interrupts */
+       rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+
+       /* read current time offset */
+       offset = gpbr_readl(rtc);
+
+       /* store the new base time in a battery backup register */
+       secs += 1;
+       gpbr_writel(rtc, secs);
+
+       /* adjust the alarm time for the new base */
+       alarm = rtt_readl(rtc, AR);
+       if (alarm != ALARM_DISABLED) {
+               if (offset > secs) {
+                       /* time jumped backwards, increase time until alarm */
+                       alarm += (offset - secs);
+               } else if ((alarm + offset) > secs) {
+                       /* time jumped forwards, decrease time until alarm */
+                       alarm -= (secs - offset);
+               } else {
+                       /* time jumped past the alarm, disable alarm */
+                       alarm = ALARM_DISABLED;
+                       mr &= ~AT91_RTT_ALMIEN;
+               }
+               rtt_writel(rtc, AR, alarm);
+       }
+
+       /* reset the timer, and re-enable interrupts */
+       rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST);
+
+       return 0;
+}
+
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       u32 alarm = rtt_readl(rtc, AR);
+       u32 offset;
+
+       offset = gpbr_readl(rtc);
+       if (offset == 0)
+               return -EILSEQ;
+
+       memset(alrm, 0, sizeof(alrm));
+       if (alarm != ALARM_DISABLED && offset != 0) {
+               rtc_time_to_tm(offset + alarm, tm);
+
+               dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm",
+                       1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+                       tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+               if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN)
+                       alrm->enabled = 1;
+       }
+
+       return 0;
+}
+
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       unsigned long secs;
+       u32 offset;
+       u32 mr;
+       int err;
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err != 0)
+               return err;
+
+       offset = gpbr_readl(rtc);
+       if (offset == 0) {
+               /* time is not set */
+               return -EILSEQ;
+       }
+       mr = rtt_readl(rtc, MR);
+       rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+
+       /* alarm in the past? finish and leave disabled */
+       if (secs <= offset) {
+               rtt_writel(rtc, AR, ALARM_DISABLED);
+               return 0;
+       }
+
+       /* else set alarm and maybe enable it */
+       rtt_writel(rtc, AR, secs - offset);
+       if (alrm->enabled)
+               rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+
+       dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm",
+               tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+               tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       int ret = 0;
+       u32 mr = rtt_readl(rtc, MR);
+
+       dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
+
+       switch (cmd) {
+       case RTC_AIE_OFF:               /* alarm off */
+               rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+               break;
+       case RTC_AIE_ON:                /* alarm on */
+               rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
+               break;
+       case RTC_UIE_OFF:               /* update off */
+               rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+               break;
+       case RTC_UIE_ON:                /* update on */
+               rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+       struct sam9_rtc *rtc = dev_get_drvdata(dev);
+       u32 mr = mr = rtt_readl(rtc, MR);
+
+       seq_printf(seq, "update_IRQ\t: %s\n",
+                       (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
+       return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
+{
+       struct sam9_rtc *rtc = _rtc;
+       u32 sr, mr;
+       unsigned long events = 0;
+
+       /* Shared interrupt may be for another device.  Note: reading
+        * SR clears it, so we must only read it in this irq handler!
+        */
+       mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       sr = rtt_readl(rtc, SR) & mr;
+       if (!sr)
+               return IRQ_NONE;
+
+       /* alarm status */
+       if (sr & AT91_RTT_ALMS)
+               events |= (RTC_AF | RTC_IRQF);
+
+       /* timer update/increment */
+       if (sr & AT91_RTT_RTTINC)
+               events |= (RTC_UF | RTC_IRQF);
+
+       rtc_update_irq(rtc->rtcdev, 1, events);
+
+       pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__,
+               events >> 8, events & 0x000000FF);
+
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops at91_rtc_ops = {
+       .ioctl          = at91_rtc_ioctl,
+       .read_time      = at91_rtc_readtime,
+       .set_time       = at91_rtc_settime,
+       .read_alarm     = at91_rtc_readalarm,
+       .set_alarm      = at91_rtc_setalarm,
+       .proc           = at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+       struct resource *r;
+       struct sam9_rtc *rtc;
+       int             ret;
+       u32             mr;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r)
+               return -ENODEV;
+
+       rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, rtc);
+       rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS);
+       rtc->rtt += r->start;
+
+       mr = rtt_readl(rtc, MR);
+
+       /* unless RTT is counting at 1 Hz, re-initialize it */
+       if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
+               mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
+               gpbr_writel(rtc, 0);
+       }
+
+       /* disable all interrupts (same as on shutdown path) */
+       mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       rtt_writel(rtc, MR, mr);
+
+       rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
+                               &at91_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtcdev)) {
+               ret = PTR_ERR(rtc->rtcdev);
+               goto fail;
+       }
+
+       /* register irq handler after we know what name we'll use */
+       ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+                               IRQF_DISABLED | IRQF_SHARED,
+                               rtc->rtcdev->dev.bus_id, rtc);
+       if (ret) {
+               dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
+               rtc_device_unregister(rtc->rtcdev);
+               goto fail;
+       }
+
+       /* NOTE:  sam9260 rev A silicon has a ROM bug which resets the
+        * RTT on at least some reboots.  If you have that chip, you must
+        * initialize the time from some external source like a GPS, wall
+        * clock, discrete RTC, etc
+        */
+
+       if (gpbr_readl(rtc) == 0)
+               dev_warn(&pdev->dev, "%s: SET TIME!\n",
+                               rtc->rtcdev->dev.bus_id);
+
+       return 0;
+
+fail:
+       platform_set_drvdata(pdev, NULL);
+       kfree(rtc);
+       return ret;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __exit at91_rtc_remove(struct platform_device *pdev)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr = rtt_readl(rtc, MR);
+
+       /* disable all interrupts */
+       rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+       free_irq(AT91_ID_SYS, rtc);
+
+       rtc_device_unregister(rtc->rtcdev);
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(rtc);
+       return 0;
+}
+
+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr = rtt_readl(rtc, MR);
+
+       rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       rtt_writel(rtc, MR, mr & ~rtc->imr);
+}
+
+#ifdef CONFIG_PM
+
+/* AT91SAM9 RTC Power management control */
+
+static int at91_rtc_suspend(struct platform_device *pdev,
+                                       pm_message_t state)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr = rtt_readl(rtc, MR);
+
+       /*
+        * This IRQ is shared with DBGU and other hardware which isn't
+        * necessarily a wakeup event source.
+        */
+       rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
+       if (rtc->imr) {
+               if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
+                       enable_irq_wake(AT91_ID_SYS);
+                       /* don't let RTTINC cause wakeups */
+                       if (mr & AT91_RTT_RTTINCIEN)
+                               rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
+               } else
+                       rtt_writel(rtc, MR, mr & ~rtc->imr);
+       }
+
+       return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+       struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+       u32             mr;
+
+       if (rtc->imr) {
+               if (device_may_wakeup(&pdev->dev))
+                       disable_irq_wake(AT91_ID_SYS);
+               mr = rtt_readl(rtc, MR);
+               rtt_writel(rtc, MR, mr | rtc->imr);
+       }
+
+       return 0;
+}
+#else
+#define at91_rtc_suspend       NULL
+#define at91_rtc_resume                NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+       .driver.name    = "rtc-at91sam9",
+       .driver.owner   = THIS_MODULE,
+       .remove         = __exit_p(at91_rtc_remove),
+       .shutdown       = at91_rtc_shutdown,
+       .suspend        = at91_rtc_suspend,
+       .resume         = at91_rtc_resume,
+};
+
+/* Chips can have more than one RTT module, and they can be used for more
+ * than just RTCs.  So we can't just register as "the" RTT driver.
+ *
+ * A normal approach in such cases is to create a library to allocate and
+ * free the modules.  Here we just use bus_find_device() as like such a
+ * library, binding directly ... no runtime "library" footprint is needed.
+ */
+static int __init at91_rtc_match(struct device *dev, void *v)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       int ret;
+
+       /* continue searching if this isn't the RTT we need */
+       if (strcmp("at91_rtt", pdev->name) != 0
+                       || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
+               goto fail;
+
+       /* else we found it ... but fail unless we can bind to the RTC driver */
+       if (dev->driver) {
+               dev_dbg(dev, "busy, can't use as RTC!\n");
+               goto fail;
+       }
+       dev->driver = &at91_rtc_driver.driver;
+       if (device_attach(dev) == 0) {
+               dev_dbg(dev, "can't attach RTC!\n");
+               goto fail;
+       }
+       ret = at91_rtc_probe(pdev);
+       if (ret == 0)
+               return true;
+
+       dev_dbg(dev, "RTC probe err %d!\n", ret);
+fail:
+       return false;
+}
+
+static int __init at91_rtc_init(void)
+{
+       int status;
+       struct device *rtc;
+
+       status = platform_driver_register(&at91_rtc_driver);
+       if (status)
+               return status;
+       rtc = bus_find_device(&platform_bus_type, NULL,
+                       NULL, at91_rtc_match);
+       if (!rtc)
+               platform_driver_unregister(&at91_rtc_driver);
+       return rtc ? 0 : -ENODEV;
+}
+module_init(at91_rtc_init);
+
+static void __exit at91_rtc_exit(void)
+{
+       platform_driver_unregister(&at91_rtc_driver);
+}
+module_exit(at91_rtc_exit);
+
+
+MODULE_AUTHOR("Michel Benoit");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");
+MODULE_LICENSE("GPL");
index 1aa709d..d90ba86 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Blackfin On-Chip Real Time Clock Driver
- *  Supports BF53[123]/BF53[467]/BF54[2489]
+ *  Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789]
  *
  * Copyright 2004-2007 Analog Devices Inc.
  *
  * writes to clear status registers complete immediately.
  */
 
-#include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/bcd.h>
-#include <linux/rtc.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/rtc.h>
 #include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
 
 #include <asm/blackfin.h>
 
-#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args)
-#define stampit() stamp("here i am")
+#define dev_dbg_stamp(dev) dev_dbg(dev, "%s:%i: here i am\n", __func__, __LINE__)
 
 struct bfin_rtc {
        struct rtc_device *rtc_dev;
        struct rtc_time rtc_alarm;
-       spinlock_t lock;
+       u16 rtc_wrote_regs;
 };
 
 /* Bit values for the ISTAT / ICTL registers */
@@ -72,7 +71,7 @@ struct bfin_rtc {
 #define SEC_BITS_OFF    0
 
 /* Some helper functions to convert between the common RTC notion of time
- * and the internal Blackfin notion that is stored in 32bits.
+ * and the internal Blackfin notion that is encoded in 32bits.
  */
 static inline u32 rtc_time_to_bfin(unsigned long now)
 {
@@ -97,7 +96,10 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
        rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm);
 }
 
-/* Wait for the previous write to a RTC register to complete.
+/**
+ *     bfin_rtc_sync_pending - make sure pending writes have complete
+ *
+ * Wait for the previous write to a RTC register to complete.
  * Unfortunately, we can't sleep here as that introduces a race condition when
  * turning on interrupt events.  Consider this:
  *  - process sets alarm
@@ -112,188 +114,202 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
  * If anyone can point out the obvious solution here, i'm listening :).  This
  * shouldn't be an issue on an SMP or preempt system as this function should
  * only be called with the rtc lock held.
+ *
+ * Other options:
+ *  - disable PREN so the sync happens at 32.768kHZ ... but this changes the
+ *    inc rate for all RTC registers from 1HZ to 32.768kHZ ...
+ *  - use the write complete IRQ
  */
-static void rtc_bfin_sync_pending(void)
+/*
+static void bfin_rtc_sync_pending_polled(void)
 {
-       stampit();
-       while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) {
+       while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE))
                if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))
                        break;
-       }
        bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
 }
+*/
+static DECLARE_COMPLETION(bfin_write_complete);
+static void bfin_rtc_sync_pending(struct device *dev)
+{
+       dev_dbg_stamp(dev);
+       while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)
+               wait_for_completion_timeout(&bfin_write_complete, HZ * 5);
+       dev_dbg_stamp(dev);
+}
 
-static void rtc_bfin_reset(struct bfin_rtc *rtc)
+/**
+ *     bfin_rtc_reset - set RTC to sane/known state
+ *
+ * Initialize the RTC.  Enable pre-scaler to scale RTC clock
+ * to 1Hz and clear interrupt/status registers.
+ */
+static void bfin_rtc_reset(struct device *dev)
 {
-       /* Initialize the RTC. Enable pre-scaler to scale RTC clock
-        * to 1Hz and clear interrupt/status registers. */
-       spin_lock_irq(&rtc->lock);
-       rtc_bfin_sync_pending();
+       struct bfin_rtc *rtc = dev_get_drvdata(dev);
+       dev_dbg_stamp(dev);
+       bfin_rtc_sync_pending(dev);
        bfin_write_RTC_PREN(0x1);
-       bfin_write_RTC_ICTL(0);
+       bfin_write_RTC_ICTL(RTC_ISTAT_WRITE_COMPLETE);
        bfin_write_RTC_SWCNT(0);
        bfin_write_RTC_ALARM(0);
        bfin_write_RTC_ISTAT(0xFFFF);
-       spin_unlock_irq(&rtc->lock);
+       rtc->rtc_wrote_regs = 0;
 }
 
+/**
+ *     bfin_rtc_interrupt - handle interrupt from RTC
+ *
+ * Since we handle all RTC events here, we have to make sure the requested
+ * interrupt is enabled (in RTC_ICTL) as the event status register (RTC_ISTAT)
+ * always gets updated regardless of the interrupt being enabled.  So when one
+ * even we care about (e.g. stopwatch) goes off, we don't want to turn around
+ * and say that other events have happened as well (e.g. second).  We do not
+ * have to worry about pending writes to the RTC_ICTL register as interrupts
+ * only fire if they are enabled in the RTC_ICTL register.
+ */
 static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
 {
-       struct platform_device *pdev = to_platform_device(dev_id);
-       struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+       struct device *dev = dev_id;
+       struct bfin_rtc *rtc = dev_get_drvdata(dev);
        unsigned long events = 0;
-       u16 rtc_istat;
-
-       stampit();
+       bool write_complete = false;
+       u16 rtc_istat, rtc_ictl;
 
-       spin_lock_irq(&rtc->lock);
+       dev_dbg_stamp(dev);
 
        rtc_istat = bfin_read_RTC_ISTAT();
+       rtc_ictl = bfin_read_RTC_ICTL();
 
-       if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
-               bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
-               events |= RTC_AF | RTC_IRQF;
+       if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) {
+               bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
+               write_complete = true;
+               complete(&bfin_write_complete);
        }
 
-       if (rtc_istat & RTC_ISTAT_STOPWATCH) {
-               bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
-               events |= RTC_PF | RTC_IRQF;
-               bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+       if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+               if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+                       bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+                       events |= RTC_AF | RTC_IRQF;
+               }
        }
 
-       if (rtc_istat & RTC_ISTAT_SEC) {
-               bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
-               events |= RTC_UF | RTC_IRQF;
+       if (rtc_ictl & RTC_ISTAT_STOPWATCH) {
+               if (rtc_istat & RTC_ISTAT_STOPWATCH) {
+                       bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+                       events |= RTC_PF | RTC_IRQF;
+                       bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+               }
        }
 
-       rtc_update_irq(rtc->rtc_dev, 1, events);
+       if (rtc_ictl & RTC_ISTAT_SEC) {
+               if (rtc_istat & RTC_ISTAT_SEC) {
+                       bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+                       events |= RTC_UF | RTC_IRQF;
+               }
+       }
 
-       spin_unlock_irq(&rtc->lock);
+       if (events)
+               rtc_update_irq(rtc->rtc_dev, 1, events);
 
-       return IRQ_HANDLED;
+       if (write_complete || events)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
 }
 
 static int bfin_rtc_open(struct device *dev)
 {
-       struct bfin_rtc *rtc = dev_get_drvdata(dev);
        int ret;
 
-       stampit();
+       dev_dbg_stamp(dev);
 
-       ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev);
-       if (unlikely(ret)) {
-               dev_err(dev, "request RTC IRQ failed with %d\n", ret);
-               return ret;
-       }
-
-       rtc_bfin_reset(rtc);
+       ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev);
+       if (!ret)
+               bfin_rtc_reset(dev);
 
        return ret;
 }
 
 static void bfin_rtc_release(struct device *dev)
 {
-       struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       rtc_bfin_reset(rtc);
+       dev_dbg_stamp(dev);
+       bfin_rtc_reset(dev);
        free_irq(IRQ_RTC, dev);
 }
 
+static void bfin_rtc_int_set(struct bfin_rtc *rtc, u16 rtc_int)
+{
+       bfin_write_RTC_ISTAT(rtc_int);
+       bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int);
+}
+static void bfin_rtc_int_clear(struct bfin_rtc *rtc, u16 rtc_int)
+{
+       bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int);
+}
+static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc)
+{
+       /* Blackfin has different bits for whether the alarm is
+        * more than 24 hours away.
+        */
+       bfin_rtc_int_set(rtc, (rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY));
+}
 static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
+       int ret = 0;
+
+       dev_dbg_stamp(dev);
 
-       stampit();
+       bfin_rtc_sync_pending(dev);
 
        switch (cmd) {
        case RTC_PIE_ON:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH);
                bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               break;
        case RTC_PIE_OFF:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_SWCNT(0);
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_clear(rtc, ~RTC_ISTAT_STOPWATCH);
+               break;
 
        case RTC_UIE_ON:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_set(rtc, RTC_ISTAT_SEC);
+               break;
        case RTC_UIE_OFF:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC);
-               spin_unlock_irq(&rtc->lock);
-               return 0;
-
-       case RTC_AIE_ON: {
-               unsigned long rtc_alarm;
-               u16 which_alarm;
-               int ret = 0;
-
-               stampit();
-
-               spin_lock_irq(&rtc->lock);
-
-               rtc_bfin_sync_pending();
-               if (rtc->rtc_alarm.tm_yday == -1) {
-                       struct rtc_time now;
-                       rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now);
-                       now.tm_sec = rtc->rtc_alarm.tm_sec;
-                       now.tm_min = rtc->rtc_alarm.tm_min;
-                       now.tm_hour = rtc->rtc_alarm.tm_hour;
-                       ret = rtc_tm_to_time(&now, &rtc_alarm);
-                       which_alarm = RTC_ISTAT_ALARM;
-               } else {
-                       ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm);
-                       which_alarm = RTC_ISTAT_ALARM_DAY;
-               }
-               if (ret == 0) {
-                       bfin_write_RTC_ISTAT(which_alarm);
-                       bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
-                       bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm);
-               }
-
-               spin_unlock_irq(&rtc->lock);
-
-               return ret;
-       }
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_clear(rtc, ~RTC_ISTAT_SEC);
+               break;
+
+       case RTC_AIE_ON:
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_set_alarm(rtc);
+               break;
        case RTC_AIE_OFF:
-               stampit();
-               spin_lock_irq(&rtc->lock);
-               rtc_bfin_sync_pending();
-               bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
-               spin_unlock_irq(&rtc->lock);
-               return 0;
+               dev_dbg_stamp(dev);
+               bfin_rtc_int_clear(rtc, ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+               break;
+
+       default:
+               dev_dbg_stamp(dev);
+               ret = -ENOIOCTLCMD;
        }
 
-       return -ENOIOCTLCMD;
+       return ret;
 }
 
 static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
 
-       stampit();
+       dev_dbg_stamp(dev);
+
+       if (rtc->rtc_wrote_regs & 0x1)
+               bfin_rtc_sync_pending(dev);
 
-       spin_lock_irq(&rtc->lock);
-       rtc_bfin_sync_pending();
        rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm);
-       spin_unlock_irq(&rtc->lock);
 
        return 0;
 }
@@ -304,64 +320,79 @@ static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm)
        int ret;
        unsigned long now;
 
-       stampit();
-
-       spin_lock_irq(&rtc->lock);
+       dev_dbg_stamp(dev);
 
        ret = rtc_tm_to_time(tm, &now);
        if (ret == 0) {
-               rtc_bfin_sync_pending();
+               if (rtc->rtc_wrote_regs & 0x1)
+                       bfin_rtc_sync_pending(dev);
                bfin_write_RTC_STAT(rtc_time_to_bfin(now));
+               rtc->rtc_wrote_regs = 0x1;
        }
 
-       spin_unlock_irq(&rtc->lock);
-
        return ret;
 }
 
 static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time));
-       alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+       dev_dbg_stamp(dev);
+       alrm->time = rtc->rtc_alarm;
+       bfin_rtc_sync_pending(dev);
+       alrm->enabled = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
        return 0;
 }
 
 static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+       unsigned long rtc_alarm;
+
+       dev_dbg_stamp(dev);
+
+       if (rtc_tm_to_time(&alrm->time, &rtc_alarm))
+               return -EINVAL;
+
+       rtc->rtc_alarm = alrm->time;
+
+       bfin_rtc_sync_pending(dev);
+       bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
+       if (alrm->enabled)
+               bfin_rtc_int_set_alarm(rtc);
+
        return 0;
 }
 
 static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
 {
-#define yesno(x) (x ? "yes" : "no")
+#define yesno(x) ((x) ? "yes" : "no")
        u16 ictl = bfin_read_RTC_ICTL();
-       stampit();
-       seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM));
-       seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY));
-       seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC));
-       seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH));
-#ifdef DEBUG
-       seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT());
-       seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL());
-       seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT());
-       seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT());
-       seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM());
-       seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN());
-#endif
+       dev_dbg_stamp(dev);
+       seq_printf(seq,
+               "alarm_IRQ\t: %s\n"
+               "wkalarm_IRQ\t: %s\n"
+               "seconds_IRQ\t: %s\n"
+               "periodic_IRQ\t: %s\n",
+               yesno(ictl & RTC_ISTAT_ALARM),
+               yesno(ictl & RTC_ISTAT_ALARM_DAY),
+               yesno(ictl & RTC_ISTAT_SEC),
+               yesno(ictl & RTC_ISTAT_STOPWATCH));
        return 0;
+#undef yesno
 }
 
+/**
+ *     bfin_irq_set_freq - make sure hardware supports requested freq
+ *     @dev: pointer to RTC device structure
+ *     @freq: requested frequency rate
+ *
+ *     The Blackfin RTC can only generate periodic events at 1 per
+ *     second (1 Hz), so reject any attempt at changing it.
+ */
 static int bfin_irq_set_freq(struct device *dev, int freq)
 {
-       struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       stampit();
-       rtc->rtc_dev->irq_freq = freq;
-       return 0;
+       dev_dbg_stamp(dev);
+       return -ENOTTY;
 }
 
 static struct rtc_class_ops bfin_rtc_ops = {
@@ -381,27 +412,24 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
        struct bfin_rtc *rtc;
        int ret = 0;
 
-       stampit();
+       dev_dbg_stamp(&pdev->dev);
 
        rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
        if (unlikely(!rtc))
                return -ENOMEM;
 
-       spin_lock_init(&rtc->lock);
-
        rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
        if (unlikely(IS_ERR(rtc))) {
                ret = PTR_ERR(rtc->rtc_dev);
                goto err;
        }
-       rtc->rtc_dev->irq_freq = 0;
-       rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */
+       rtc->rtc_dev->irq_freq = 1;
 
        platform_set_drvdata(pdev, rtc);
 
        return 0;
 
-err:
+ err:
        kfree(rtc);
        return ret;
 }
@@ -428,7 +456,6 @@ static struct platform_driver bfin_rtc_driver = {
 
 static int __init bfin_rtc_init(void)
 {
-       stampit();
        return platform_driver_register(&bfin_rtc_driver);
 }
 
index 29cf145..e059f94 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/mod_devicetable.h>
 
+#ifdef CONFIG_HPET_EMULATE_RTC
+#include <asm/hpet.h>
+#endif
+
 /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
 #include <asm-generic/rtc.h>
 
+#ifndef CONFIG_HPET_EMULATE_RTC
+#define is_hpet_enabled()                      0
+#define hpet_set_alarm_time(hrs, min, sec)     do { } while (0)
+#define hpet_set_periodic_freq(arg)            0
+#define hpet_mask_rtc_irq_bit(arg)             do { } while (0)
+#define hpet_set_rtc_irq_bit(arg)              do { } while (0)
+#define hpet_rtc_timer_init()                  do { } while (0)
+#define hpet_register_irq_handler(h)           0
+#define hpet_unregister_irq_handler(h)         do { } while (0)
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+#endif
 
 struct cmos_rtc {
        struct rtc_device       *rtc;
@@ -199,6 +214,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        sec = t->time.tm_sec;
        sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
 
+       hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
        spin_lock_irq(&rtc_lock);
 
        /* next rtc irq must not be from previous alarm setting */
@@ -252,7 +268,8 @@ static int cmos_irq_set_freq(struct device *dev, int freq)
        f = 16 - f;
 
        spin_lock_irqsave(&rtc_lock, flags);
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+       if (!hpet_set_periodic_freq(freq))
+               CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
        spin_unlock_irqrestore(&rtc_lock, flags);
 
        return 0;
@@ -314,28 +331,37 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        case RTC_AIE_OFF:       /* alarm off */
                rtc_control &= ~RTC_AIE;
+               hpet_mask_rtc_irq_bit(RTC_AIE);
                break;
        case RTC_AIE_ON:        /* alarm on */
                rtc_control |= RTC_AIE;
+               hpet_set_rtc_irq_bit(RTC_AIE);
                break;
        case RTC_UIE_OFF:       /* update off */
                rtc_control &= ~RTC_UIE;
+               hpet_mask_rtc_irq_bit(RTC_UIE);
                break;
        case RTC_UIE_ON:        /* update on */
                rtc_control |= RTC_UIE;
+               hpet_set_rtc_irq_bit(RTC_UIE);
                break;
        case RTC_PIE_OFF:       /* periodic off */
                rtc_control &= ~RTC_PIE;
+               hpet_mask_rtc_irq_bit(RTC_PIE);
                break;
        case RTC_PIE_ON:        /* periodic on */
                rtc_control |= RTC_PIE;
+               hpet_set_rtc_irq_bit(RTC_PIE);
                break;
        }
-       CMOS_WRITE(rtc_control, RTC_CONTROL);
+       if (!is_hpet_enabled())
+               CMOS_WRITE(rtc_control, RTC_CONTROL);
+
        rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
        rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
        if (is_intr(rtc_intr))
                rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
        spin_unlock_irqrestore(&rtc_lock, flags);
        return 0;
 }
@@ -393,15 +419,111 @@ static const struct rtc_class_ops cmos_rtc_ops = {
 
 /*----------------------------------------------------------------*/
 
+/*
+ * All these chips have at least 64 bytes of address space, shared by
+ * RTC registers and NVRAM.  Most of those bytes of NVRAM are used
+ * by boot firmware.  Modern chips have 128 or 256 bytes.
+ */
+
+#define NVRAM_OFFSET   (RTC_REG_D + 1)
+
+static ssize_t
+cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       int     retval;
+
+       if (unlikely(off >= attr->size))
+               return 0;
+       if ((off + count) > attr->size)
+               count = attr->size - off;
+
+       spin_lock_irq(&rtc_lock);
+       for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++)
+               *buf++ = CMOS_READ(off);
+       spin_unlock_irq(&rtc_lock);
+
+       return retval;
+}
+
+static ssize_t
+cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct cmos_rtc *cmos;
+       int             retval;
+
+       cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
+       if (unlikely(off >= attr->size))
+               return -EFBIG;
+       if ((off + count) > attr->size)
+               count = attr->size - off;
+
+       /* NOTE:  on at least PCs and Ataris, the boot firmware uses a
+        * checksum on part of the NVRAM data.  That's currently ignored
+        * here.  If userspace is smart enough to know what fields of
+        * NVRAM to update, updating checksums is also part of its job.
+        */
+       spin_lock_irq(&rtc_lock);
+       for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) {
+               /* don't trash RTC registers */
+               if (off == cmos->day_alrm
+                               || off == cmos->mon_alrm
+                               || off == cmos->century)
+                       buf++;
+               else
+                       CMOS_WRITE(*buf++, off);
+       }
+       spin_unlock_irq(&rtc_lock);
+
+       return retval;
+}
+
+static struct bin_attribute nvram = {
+       .attr = {
+               .name   = "nvram",
+               .mode   = S_IRUGO | S_IWUSR,
+               .owner  = THIS_MODULE,
+       },
+
+       .read   = cmos_nvram_read,
+       .write  = cmos_nvram_write,
+       /* size gets set up later */
+};
+
+/*----------------------------------------------------------------*/
+
 static struct cmos_rtc cmos_rtc;
 
 static irqreturn_t cmos_interrupt(int irq, void *p)
 {
        u8              irqstat;
+       u8              rtc_control;
 
        spin_lock(&rtc_lock);
-       irqstat = CMOS_READ(RTC_INTR_FLAGS);
-       irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF;
+       /*
+        * In this case it is HPET RTC interrupt handler
+        * calling us, with the interrupt information
+        * passed as arg1, instead of irq.
+        */
+       if (is_hpet_enabled())
+               irqstat = (unsigned long)irq & 0xF0;
+       else {
+               irqstat = CMOS_READ(RTC_INTR_FLAGS);
+               rtc_control = CMOS_READ(RTC_CONTROL);
+               irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+       }
+
+       /* All Linux RTC alarms should be treated as if they were oneshot.
+        * Similar code may be needed in system wakeup paths, in case the
+        * alarm woke the system.
+        */
+       if (irqstat & RTC_AIE) {
+               rtc_control = CMOS_READ(RTC_CONTROL);
+               rtc_control &= ~RTC_AIE;
+               CMOS_WRITE(rtc_control, RTC_CONTROL);
+               CMOS_READ(RTC_INTR_FLAGS);
+       }
        spin_unlock(&rtc_lock);
 
        if (is_intr(irqstat)) {
@@ -412,11 +534,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
 }
 
 #ifdef CONFIG_PNP
-#define        is_pnp()        1
 #define        INITSECTION
 
 #else
-#define        is_pnp()        0
 #define        INITSECTION     __init
 #endif
 
@@ -426,6 +546,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        struct cmos_rtc_board_info      *info = dev->platform_data;
        int                             retval = 0;
        unsigned char                   rtc_control;
+       unsigned                        address_space;
 
        /* there can be only one ... */
        if (cmos_rtc.dev)
@@ -450,15 +571,36 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        cmos_rtc.irq = rtc_irq;
        cmos_rtc.iomem = ports;
 
+       /* Heuristic to deduce NVRAM size ... do what the legacy NVRAM
+        * driver did, but don't reject unknown configs.   Old hardware
+        * won't address 128 bytes, and for now we ignore the way newer
+        * chips can address 256 bytes (using two more i/o ports).
+        */
+#if    defined(CONFIG_ATARI)
+       address_space = 64;
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+       address_space = 128;
+#else
+#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
+       address_space = 128;
+#endif
+
        /* For ACPI systems extension info comes from the FADT.  On others,
         * board specific setup provides it as appropriate.  Systems where
         * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
         * some almost-clones) can provide hooks to make that behave.
+        *
+        * Note that ACPI doesn't preclude putting these registers into
+        * "extended" areas of the chip, including some that we won't yet
+        * expect CMOS_READ and friends to handle.
         */
        if (info) {
-               cmos_rtc.day_alrm = info->rtc_day_alarm;
-               cmos_rtc.mon_alrm = info->rtc_mon_alarm;
-               cmos_rtc.century = info->rtc_century;
+               if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
+                       cmos_rtc.day_alrm = info->rtc_day_alarm;
+               if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
+                       cmos_rtc.mon_alrm = info->rtc_mon_alarm;
+               if (info->rtc_century && info->rtc_century < 128)
+                       cmos_rtc.century = info->rtc_century;
 
                if (info->wake_on && info->wake_off) {
                        cmos_rtc.wake_on = info->wake_on;
@@ -485,8 +627,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
         * doesn't use 32KHz here ... for portability we might need to
         * do something about other clock frequencies.
         */
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
        cmos_rtc.rtc->irq_freq = 1024;
+       if (!hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq))
+               CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
 
        /* disable irqs.
         *
@@ -509,19 +652,39 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                goto cleanup1;
        }
 
-       if (is_valid_irq(rtc_irq))
-               retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
-                               cmos_rtc.rtc->dev.bus_id,
+       if (is_valid_irq(rtc_irq)) {
+               irq_handler_t rtc_cmos_int_handler;
+
+               if (is_hpet_enabled()) {
+                       int err;
+
+                       rtc_cmos_int_handler = hpet_rtc_interrupt;
+                       err = hpet_register_irq_handler(cmos_interrupt);
+                       if (err != 0) {
+                               printk(KERN_WARNING "hpet_register_irq_handler "
+                                               " failed in rtc_init().");
+                               goto cleanup1;
+                       }
+               } else
+                       rtc_cmos_int_handler = cmos_interrupt;
+
+               retval = request_irq(rtc_irq, rtc_cmos_int_handler,
+                               IRQF_DISABLED, cmos_rtc.rtc->dev.bus_id,
                                cmos_rtc.rtc);
-       if (retval < 0) {
-               dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
-               goto cleanup1;
+               if (retval < 0) {
+                       dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
+                       goto cleanup1;
+               }
        }
+       hpet_rtc_timer_init();
 
-       /* REVISIT optionally make 50 or 114 bytes NVRAM available,
-        * like rtc-ds1553, rtc-ds1742 ... this will often include
-        * registers for century, and day/month alarm.
-        */
+       /* export at least the first block of NVRAM */
+       nvram.size = address_space - NVRAM_OFFSET;
+       retval = sysfs_create_bin_file(&dev->kobj, &nvram);
+       if (retval < 0) {
+               dev_dbg(dev, "can't create nvram file? %d\n", retval);
+               goto cleanup2;
+       }
 
        pr_info("%s: alarms up to one %s%s\n",
                        cmos_rtc.rtc->dev.bus_id,
@@ -536,6 +699,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 
        return 0;
 
+cleanup2:
+       if (is_valid_irq(rtc_irq))
+               free_irq(rtc_irq, cmos_rtc.rtc);
 cleanup1:
        cmos_rtc.dev = NULL;
        rtc_device_unregister(cmos_rtc.rtc);
@@ -563,8 +729,12 @@ static void __exit cmos_do_remove(struct device *dev)
 
        cmos_do_shutdown();
 
-       if (is_valid_irq(cmos->irq))
+       sysfs_remove_bin_file(&dev->kobj, &nvram);
+
+       if (is_valid_irq(cmos->irq)) {
                free_irq(cmos->irq, cmos->rtc);
+               hpet_unregister_irq_handler(cmos_interrupt);
+       }
 
        rtc_device_unregister(cmos->rtc);
        cmos->rtc = NULL;
@@ -659,9 +829,12 @@ static int cmos_resume(struct device *dev)
 
 /*----------------------------------------------------------------*/
 
-/* The "CMOS" RTC normally lives on the platform_bus.  On ACPI systems,
- * the device node will always be created as a PNPACPI device.  Plus
- * pre-ACPI PCs probably list it in the PNPBIOS tables.
+/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
+ * ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs
+ * probably list them in similar PNPBIOS tables; so PNP is more common.
+ *
+ * We don't use legacy "poke at the hardware" probing.  Ancient PCs that
+ * predate even PNPBIOS should set up platform_bus devices.
  */
 
 #ifdef CONFIG_PNP
index 025c60a..90dfa0d 100644 (file)
@@ -246,6 +246,15 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
        /* if the driver does not provide the ioctl interface
         * or if that particular ioctl was not implemented
         * (-ENOIOCTLCMD), we will try to emulate here.
+        *
+        * Drivers *SHOULD NOT* provide ioctl implementations
+        * for these requests.  Instead, provide methods to
+        * support the following code, so that the RTC's main
+        * features are accessible without using ioctls.
+        *
+        * RTC and alarm times will be in UTC, by preference,
+        * but dual-booting with MS-Windows implies RTCs must
+        * use the local wall clock time.
         */
 
        switch (cmd) {
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
new file mode 100644 (file)
index 0000000..7b002ce
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Dallas DS1302 RTC Support
+ *
+ *  Copyright (C) 2002  David McCullough
+ *  Copyright (C) 2003 - 2007  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/bcd.h>
+#include <asm/rtc.h>
+
+#define DRV_NAME       "rtc-ds1302"
+#define DRV_VERSION    "0.1.0"
+
+#define        RTC_CMD_READ    0x81            /* Read command */
+#define        RTC_CMD_WRITE   0x80            /* Write command */
+
+#define RTC_ADDR_RAM0  0x20            /* Address of RAM0 */
+#define RTC_ADDR_TCR   0x08            /* Address of trickle charge register */
+#define        RTC_ADDR_YEAR   0x06            /* Address of year register */
+#define        RTC_ADDR_DAY    0x05            /* Address of day of week register */
+#define        RTC_ADDR_MON    0x04            /* Address of month register */
+#define        RTC_ADDR_DATE   0x03            /* Address of day of month register */
+#define        RTC_ADDR_HOUR   0x02            /* Address of hour register */
+#define        RTC_ADDR_MIN    0x01            /* Address of minute register */
+#define        RTC_ADDR_SEC    0x00            /* Address of second register */
+
+#define        RTC_RESET       0x1000
+#define        RTC_IODATA      0x0800
+#define        RTC_SCLK        0x0400
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+#include <asm/snapgear.h>
+#define set_dp(x)      SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
+#define get_dp()       SECUREEDGE_READ_IOPORT()
+#else
+#error "Add support for your platform"
+#endif
+
+struct ds1302_rtc {
+       struct rtc_device *rtc_dev;
+       spinlock_t lock;
+};
+
+static void ds1302_sendbits(unsigned int val)
+{
+       int i;
+
+       for (i = 8; (i); i--, val >>= 1) {
+               set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ?
+                       RTC_IODATA : 0));
+               set_dp(get_dp() | RTC_SCLK);    /* clock high */
+               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+       }
+}
+
+static unsigned int ds1302_recvbits(void)
+{
+       unsigned int val;
+       int i;
+
+       for (i = 0, val = 0; (i < 8); i++) {
+               val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
+               set_dp(get_dp() | RTC_SCLK);    /* clock high */
+               set_dp(get_dp() & ~RTC_SCLK);   /* clock low */
+       }
+
+       return val;
+}
+
+static unsigned int ds1302_readbyte(unsigned int addr)
+{
+       unsigned int val;
+
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+       set_dp(get_dp() | RTC_RESET);
+       ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
+       val = ds1302_recvbits();
+       set_dp(get_dp() & ~RTC_RESET);
+
+       return val;
+}
+
+static void ds1302_writebyte(unsigned int addr, unsigned int val)
+{
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+       set_dp(get_dp() | RTC_RESET);
+       ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
+       ds1302_sendbits(val);
+       set_dp(get_dp() & ~RTC_RESET);
+}
+
+static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+       spin_lock_irq(&rtc->lock);
+
+       tm->tm_sec      = BCD2BIN(ds1302_readbyte(RTC_ADDR_SEC));
+       tm->tm_min      = BCD2BIN(ds1302_readbyte(RTC_ADDR_MIN));
+       tm->tm_hour     = BCD2BIN(ds1302_readbyte(RTC_ADDR_HOUR));
+       tm->tm_wday     = BCD2BIN(ds1302_readbyte(RTC_ADDR_DAY));
+       tm->tm_mday     = BCD2BIN(ds1302_readbyte(RTC_ADDR_DATE));
+       tm->tm_mon      = BCD2BIN(ds1302_readbyte(RTC_ADDR_MON)) - 1;
+       tm->tm_year     = BCD2BIN(ds1302_readbyte(RTC_ADDR_YEAR));
+
+       if (tm->tm_year < 70)
+               tm->tm_year += 100;
+
+       spin_unlock_irq(&rtc->lock);
+
+       dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __FUNCTION__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
+
+       if (rtc_valid_tm(tm) < 0)
+               dev_err(dev, "invalid date\n");
+
+       return 0;
+}
+
+static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+
+       spin_lock_irq(&rtc->lock);
+
+       /* Stop RTC */
+       ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
+
+       ds1302_writebyte(RTC_ADDR_SEC, BIN2BCD(tm->tm_sec));
+       ds1302_writebyte(RTC_ADDR_MIN, BIN2BCD(tm->tm_min));
+       ds1302_writebyte(RTC_ADDR_HOUR, BIN2BCD(tm->tm_hour));
+       ds1302_writebyte(RTC_ADDR_DAY, BIN2BCD(tm->tm_wday));
+       ds1302_writebyte(RTC_ADDR_DATE, BIN2BCD(tm->tm_mday));
+       ds1302_writebyte(RTC_ADDR_MON, BIN2BCD(tm->tm_mon + 1));
+       ds1302_writebyte(RTC_ADDR_YEAR, BIN2BCD(tm->tm_year % 100));
+
+       /* Start RTC */
+       ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
+
+       spin_unlock_irq(&rtc->lock);
+
+       return 0;
+}
+
+static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd,
+                           unsigned long arg)
+{
+       switch (cmd) {
+#ifdef RTC_SET_CHARGE
+       case RTC_SET_CHARGE:
+       {
+               struct ds1302_rtc *rtc = dev_get_drvdata(dev);
+               int tcs_val;
+
+               if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int)))
+                       return -EFAULT;
+
+               spin_lock_irq(&rtc->lock);
+               ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf));
+               spin_unlock_irq(&rtc->lock);
+               return 0;
+       }
+#endif
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static struct rtc_class_ops ds1302_rtc_ops = {
+       .read_time      = ds1302_rtc_read_time,
+       .set_time       = ds1302_rtc_set_time,
+       .ioctl          = ds1302_rtc_ioctl,
+};
+
+static int __devinit ds1302_rtc_probe(struct platform_device *pdev)
+{
+       struct ds1302_rtc *rtc;
+       int ret;
+
+       /* Reset */
+       set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+       /* Write a magic value to the DS1302 RAM, and see if it sticks. */
+       ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
+       if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42)
+               return -ENODEV;
+
+       rtc = kzalloc(sizeof(struct ds1302_rtc), GFP_KERNEL);
+       if (unlikely(!rtc))
+               return -ENOMEM;
+
+       spin_lock_init(&rtc->lock);
+       rtc->rtc_dev = rtc_device_register("ds1302", &pdev->dev,
+                                          &ds1302_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc_dev)) {
+               ret = PTR_ERR(rtc->rtc_dev);
+               goto out;
+       }
+
+       platform_set_drvdata(pdev, rtc);
+
+       return 0;
+out:
+       kfree(rtc);
+       return ret;
+}
+
+static int __devexit ds1302_rtc_remove(struct platform_device *pdev)
+{
+       struct ds1302_rtc *rtc = platform_get_drvdata(pdev);
+
+       if (likely(rtc->rtc_dev))
+               rtc_device_unregister(rtc->rtc_dev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(rtc);
+
+       return 0;
+}
+
+static struct platform_driver ds1302_platform_driver = {
+       .driver         = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ds1302_rtc_probe,
+       .remove         = __devexit_p(ds1302_rtc_remove),
+};
+
+static int __init ds1302_rtc_init(void)
+{
+       return platform_driver_register(&ds1302_platform_driver);
+}
+
+static void __exit ds1302_rtc_exit(void)
+{
+       platform_driver_unregister(&ds1302_platform_driver);
+}
+
+module_init(ds1302_rtc_init);
+module_exit(ds1302_rtc_exit);
+
+MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Paul Mundt, David McCullough");
+MODULE_LICENSE("GPL v2");
index bc1c7fe..f389a28 100644 (file)
@@ -256,7 +256,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
        struct i2c_msg          msg[2];
        int                     result;
 
-       client = to_i2c_client(container_of(kobj, struct device, kobj));
+       client = kobj_to_i2c_client(kobj);
        ds1307 = i2c_get_clientdata(client);
 
        if (unlikely(off >= NVRAM_SIZE))
@@ -294,7 +294,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
        u8                      buffer[NVRAM_SIZE + 1];
        int                     ret;
 
-       client = to_i2c_client(container_of(kobj, struct device, kobj));
+       client = kobj_to_i2c_client(kobj);
 
        if (unlikely(off >= NVRAM_SIZE))
                return -EFBIG;
@@ -412,11 +412,6 @@ read_rtc:
         */
        tmp = ds1307->regs[DS1307_REG_SECS];
        switch (ds1307->type) {
-       case ds_1340:
-               /* FIXME read register with DS1340_BIT_OSF, use that to
-                * trigger the "set time" warning (*after* restarting the
-                * oscillator!) instead of this weaker ds1307/m41t00 test.
-                */
        case ds_1307:
        case m41t00:
                /* clock halted?  turn it on, so clock can tick. */
@@ -440,6 +435,24 @@ read_rtc:
                        goto read_rtc;
                }
                break;
+       case ds_1340:
+               /* clock halted?  turn it on, so clock can tick. */
+               if (tmp & DS1340_BIT_nEOSC)
+                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+
+               tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
+               if (tmp < 0) {
+                       pr_debug("read error %d\n", tmp);
+                       err = -EIO;
+                       goto exit_free;
+               }
+
+               /* oscillator fault?  clear flag, and warn */
+               if (tmp & DS1340_BIT_OSF) {
+                       i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
+                       dev_warn(&client->dev, "SET TIME!\n");
+               }
+               break;
        case ds_1337:
        case ds_1339:
                break;
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
new file mode 100644 (file)
index 0000000..d74b808
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * An rtc driver for the Dallas DS1511
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Real time clock driver for the Dallas 1511 chip, which also
+ * contains a watchdog timer.  There is a tiny amount of code that
+ * platform code could use to mess with the watchdog device a little
+ * bit, but not a full watchdog driver.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.6"
+
+enum ds1511reg {
+       DS1511_SEC = 0x0,
+       DS1511_MIN = 0x1,
+       DS1511_HOUR = 0x2,
+       DS1511_DOW = 0x3,
+       DS1511_DOM = 0x4,
+       DS1511_MONTH = 0x5,
+       DS1511_YEAR = 0x6,
+       DS1511_CENTURY = 0x7,
+       DS1511_AM1_SEC = 0x8,
+       DS1511_AM2_MIN = 0x9,
+       DS1511_AM3_HOUR = 0xa,
+       DS1511_AM4_DATE = 0xb,
+       DS1511_WD_MSEC = 0xc,
+       DS1511_WD_SEC = 0xd,
+       DS1511_CONTROL_A = 0xe,
+       DS1511_CONTROL_B = 0xf,
+       DS1511_RAMADDR_LSB = 0x10,
+       DS1511_RAMDATA = 0x13
+};
+
+#define DS1511_BLF1    0x80
+#define DS1511_BLF2    0x40
+#define DS1511_PRS     0x20
+#define DS1511_PAB     0x10
+#define DS1511_TDF     0x08
+#define DS1511_KSF     0x04
+#define DS1511_WDF     0x02
+#define DS1511_IRQF    0x01
+#define DS1511_TE      0x80
+#define DS1511_CS      0x40
+#define DS1511_BME     0x20
+#define DS1511_TPE     0x10
+#define DS1511_TIE     0x08
+#define DS1511_KIE     0x04
+#define DS1511_WDE     0x02
+#define DS1511_WDS     0x01
+#define DS1511_RAM_MAX 0xff
+
+#define RTC_CMD                DS1511_CONTROL_B
+#define RTC_CMD1       DS1511_CONTROL_A
+
+#define RTC_ALARM_SEC  DS1511_AM1_SEC
+#define RTC_ALARM_MIN  DS1511_AM2_MIN
+#define RTC_ALARM_HOUR DS1511_AM3_HOUR
+#define RTC_ALARM_DATE DS1511_AM4_DATE
+
+#define RTC_SEC                DS1511_SEC
+#define RTC_MIN                DS1511_MIN
+#define RTC_HOUR       DS1511_HOUR
+#define RTC_DOW                DS1511_DOW
+#define RTC_DOM                DS1511_DOM
+#define RTC_MON                DS1511_MONTH
+#define RTC_YEAR       DS1511_YEAR
+#define RTC_CENTURY    DS1511_CENTURY
+
+#define RTC_TIE        DS1511_TIE
+#define RTC_TE DS1511_TE
+
+struct rtc_plat_data {
+       struct rtc_device *rtc;
+       void __iomem *ioaddr;           /* virtual base address */
+       unsigned long baseaddr;         /* physical base address */
+       int size;                               /* amount of memory mapped */
+       int irq;
+       unsigned int irqen;
+       int alrm_sec;
+       int alrm_min;
+       int alrm_hour;
+       int alrm_mday;
+};
+
+static DEFINE_SPINLOCK(ds1511_lock);
+
+static __iomem char *ds1511_base;
+static u32 reg_spacing = 1;
+
+ static noinline void
+rtc_write(uint8_t val, uint32_t reg)
+{
+       writeb(val, ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_write_alarm(uint8_t val, enum ds1511reg reg)
+{
+       rtc_write((val | 0x80), reg);
+}
+
+ static noinline uint8_t
+rtc_read(enum ds1511reg reg)
+{
+       return readb(ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_disable_update(void)
+{
+       rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
+}
+
+ static void
+rtc_enable_update(void)
+{
+       rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
+}
+
+/*
+ * #define DS1511_WDOG_RESET_SUPPORT
+ *
+ * Uncomment this if you want to use these routines in
+ * some platform code.
+ */
+#ifdef DS1511_WDOG_RESET_SUPPORT
+/*
+ * just enough code to set the watchdog timer so that it
+ * will reboot the system
+ */
+ void
+ds1511_wdog_set(unsigned long deciseconds)
+{
+       /*
+        * the wdog timer can take 99.99 seconds
+        */
+       deciseconds %= 10000;
+       /*
+        * set the wdog values in the wdog registers
+        */
+       rtc_write(BIN2BCD(deciseconds % 100), DS1511_WD_MSEC);
+       rtc_write(BIN2BCD(deciseconds / 100), DS1511_WD_SEC);
+       /*
+        * set wdog enable and wdog 'steering' bit to issue a reset
+        */
+       rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
+}
+
+ void
+ds1511_wdog_disable(void)
+{
+       /*
+        * clear wdog enable and wdog 'steering' bits
+        */
+       rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
+       /*
+        * clear the wdog counter
+        */
+       rtc_write(0, DS1511_WD_MSEC);
+       rtc_write(0, DS1511_WD_SEC);
+}
+#endif
+
+/*
+ * set the rtc chip's idea of the time.
+ * stupidly, some callers call with year unmolested;
+ * and some call with  year = year - 1900.  thanks.
+ */
+ int
+ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+       u8 mon, day, dow, hrs, min, sec, yrs, cen;
+       unsigned int flags;
+
+       /*
+        * won't have to change this for a while
+        */
+       if (rtc_tm->tm_year < 1900) {
+               rtc_tm->tm_year += 1900;
+       }
+
+       if (rtc_tm->tm_year < 1970) {
+               return -EINVAL;
+       }
+       yrs = rtc_tm->tm_year % 100;
+       cen = rtc_tm->tm_year / 100;
+       mon = rtc_tm->tm_mon + 1;   /* tm_mon starts at zero */
+       day = rtc_tm->tm_mday;
+       dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */
+       hrs = rtc_tm->tm_hour;
+       min = rtc_tm->tm_min;
+       sec = rtc_tm->tm_sec;
+
+       if ((mon > 12) || (day == 0)) {
+               return -EINVAL;
+       }
+
+       if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) {
+               return -EINVAL;
+       }
+
+       if ((hrs >= 24) || (min >= 60) || (sec >= 60)) {
+               return -EINVAL;
+       }
+
+       /*
+        * each register is a different number of valid bits
+        */
+       sec = BIN2BCD(sec) & 0x7f;
+       min = BIN2BCD(min) & 0x7f;
+       hrs = BIN2BCD(hrs) & 0x3f;
+       day = BIN2BCD(day) & 0x3f;
+       mon = BIN2BCD(mon) & 0x1f;
+       yrs = BIN2BCD(yrs) & 0xff;
+       cen = BIN2BCD(cen) & 0xff;
+
+       spin_lock_irqsave(&ds1511_lock, flags);
+       rtc_disable_update();
+       rtc_write(cen, RTC_CENTURY);
+       rtc_write(yrs, RTC_YEAR);
+       rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON);
+       rtc_write(day, RTC_DOM);
+       rtc_write(hrs, RTC_HOUR);
+       rtc_write(min, RTC_MIN);
+       rtc_write(sec, RTC_SEC);
+       rtc_write(dow, RTC_DOW);
+       rtc_enable_update();
+       spin_unlock_irqrestore(&ds1511_lock, flags);
+
+       return 0;
+}
+
+ int
+ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+       unsigned int century;
+       unsigned int flags;
+
+       spin_lock_irqsave(&ds1511_lock, flags);
+       rtc_disable_update();
+
+       rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
+       rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
+       rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
+       rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
+       rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
+       rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
+       rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
+       century = rtc_read(RTC_CENTURY);
+
+       rtc_enable_update();
+       spin_unlock_irqrestore(&ds1511_lock, flags);
+
+       rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec);
+       rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min);
+       rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour);
+       rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday);
+       rtc_tm->tm_wday = BCD2BIN(rtc_tm->tm_wday);
+       rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon);
+       rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year);
+       century = BCD2BIN(century) * 100;
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+       century += rtc_tm->tm_year;
+       rtc_tm->tm_year = century - 1900;
+
+       rtc_tm->tm_mon--;
+
+       if (rtc_valid_tm(rtc_tm) < 0) {
+               dev_err(dev, "retrieved date/time is not valid.\n");
+               rtc_time_to_tm(0, rtc_tm);
+       }
+       return 0;
+}
+
+/*
+ * write the alarm register settings
+ *
+ * we only have the use to interrupt every second, otherwise
+ * known as the update interrupt, or the interrupt if the whole
+ * date/hours/mins/secs matches.  the ds1511 has many more
+ * permutations, but the kernel doesn't.
+ */
+ static void
+ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+       rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_mday) & 0x3f,
+              RTC_ALARM_DATE);
+       rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_hour) & 0x3f,
+              RTC_ALARM_HOUR);
+       rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_min) & 0x7f,
+              RTC_ALARM_MIN);
+       rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+              0x80 : BIN2BCD(pdata->alrm_sec) & 0x7f,
+              RTC_ALARM_SEC);
+       rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
+       rtc_read(RTC_CMD1);     /* clear interrupts */
+       spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+ static int
+ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0) {
+               return -EINVAL;
+       }
+       pdata->alrm_mday = alrm->time.tm_mday;
+       pdata->alrm_hour = alrm->time.tm_hour;
+       pdata->alrm_min = alrm->time.tm_min;
+       pdata->alrm_sec = alrm->time.tm_sec;
+       if (alrm->enabled) {
+               pdata->irqen |= RTC_AF;
+       }
+       ds1511_rtc_update_alarm(pdata);
+       return 0;
+}
+
+ static int
+ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0) {
+               return -EINVAL;
+       }
+       alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+       alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+       alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+       alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+       alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+       return 0;
+}
+
+ static irqreturn_t
+ds1511_interrupt(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       unsigned long events = RTC_IRQF;
+
+       /*
+        * read and clear interrupt
+        */
+       if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) {
+               return IRQ_NONE;
+       }
+       if (rtc_read(RTC_ALARM_SEC) & 0x80) {
+               events |= RTC_UF;
+       } else {
+               events |= RTC_AF;
+       }
+       rtc_update_irq(pdata->rtc, 1, events);
+       return IRQ_HANDLED;
+}
+
+ static void
+ds1511_rtc_release(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq >= 0) {
+               pdata->irqen = 0;
+               ds1511_rtc_update_alarm(pdata);
+       }
+}
+
+ static int
+ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       if (pdata->irq < 0) {
+               return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+       }
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               pdata->irqen &= ~RTC_AF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       case RTC_AIE_ON:
+               pdata->irqen |= RTC_AF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       case RTC_UIE_OFF:
+               pdata->irqen &= ~RTC_UF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       case RTC_UIE_ON:
+               pdata->irqen |= RTC_UF;
+               ds1511_rtc_update_alarm(pdata);
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static const struct rtc_class_ops ds1511_rtc_ops = {
+       .read_time      = ds1511_rtc_read_time,
+       .set_time       = ds1511_rtc_set_time,
+       .read_alarm     = ds1511_rtc_read_alarm,
+       .set_alarm      = ds1511_rtc_set_alarm,
+       .release        = ds1511_rtc_release,
+       .ioctl          = ds1511_rtc_ioctl,
+};
+
+ static ssize_t
+ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
+                               char *buf, loff_t pos, size_t size)
+{
+       ssize_t count;
+
+       /*
+        * if count is more than one, turn on "burst" mode
+        * turn it off when you're done
+        */
+       if (size > 1) {
+               rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+       }
+       if (pos > DS1511_RAM_MAX) {
+               pos = DS1511_RAM_MAX;
+       }
+       if (size + pos > DS1511_RAM_MAX + 1) {
+               size = DS1511_RAM_MAX - pos + 1;
+       }
+       rtc_write(pos, DS1511_RAMADDR_LSB);
+       for (count = 0; size > 0; count++, size--) {
+               *buf++ = rtc_read(DS1511_RAMDATA);
+       }
+       if (count > 1) {
+               rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+       }
+       return count;
+}
+
+ static ssize_t
+ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr,
+                               char *buf, loff_t pos, size_t size)
+{
+       ssize_t count;
+
+       /*
+        * if count is more than one, turn on "burst" mode
+        * turn it off when you're done
+        */
+       if (size > 1) {
+               rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
+       }
+       if (pos > DS1511_RAM_MAX) {
+               pos = DS1511_RAM_MAX;
+       }
+       if (size + pos > DS1511_RAM_MAX + 1) {
+               size = DS1511_RAM_MAX - pos + 1;
+       }
+       rtc_write(pos, DS1511_RAMADDR_LSB);
+       for (count = 0; size > 0; count++, size--) {
+               rtc_write(*buf++, DS1511_RAMDATA);
+       }
+       if (count > 1) {
+               rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
+       }
+       return count;
+}
+
+static struct bin_attribute ds1511_nvram_attr = {
+       .attr = {
+               .name = "nvram",
+               .mode = S_IRUGO | S_IWUGO,
+               .owner = THIS_MODULE,
+       },
+       .size = DS1511_RAM_MAX,
+       .read = ds1511_nvram_read,
+       .write = ds1511_nvram_write,
+};
+
+ static int __devinit
+ds1511_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       struct resource *res;
+       struct rtc_plat_data *pdata = NULL;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               return -ENODEV;
+       }
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               return -ENOMEM;
+       }
+       pdata->irq = -1;
+       pdata->size = res->end - res->start + 1;
+       if (!request_mem_region(res->start, pdata->size, pdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
+       pdata->baseaddr = res->start;
+       pdata->size = pdata->size;
+       ds1511_base = ioremap(pdata->baseaddr, pdata->size);
+       if (!ds1511_base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       pdata->ioaddr = ds1511_base;
+       pdata->irq = platform_get_irq(pdev, 0);
+
+       /*
+        * turn on the clock and the crystal, etc.
+        */
+       rtc_write(0, RTC_CMD);
+       rtc_write(0, RTC_CMD1);
+       /*
+        * clear the wdog counter
+        */
+       rtc_write(0, DS1511_WD_MSEC);
+       rtc_write(0, DS1511_WD_SEC);
+       /*
+        * start the clock
+        */
+       rtc_enable_update();
+
+       /*
+        * check for a dying bat-tree
+        */
+       if (rtc_read(RTC_CMD1) & DS1511_BLF1) {
+               dev_warn(&pdev->dev, "voltage-low detected.\n");
+       }
+
+       /*
+        * if the platform has an interrupt in mind for this device,
+        * then by all means, set it
+        */
+       if (pdata->irq >= 0) {
+               rtc_read(RTC_CMD1);
+               if (request_irq(pdata->irq, ds1511_interrupt,
+                       IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
+
+                       dev_warn(&pdev->dev, "interrupt not available.\n");
+                       pdata->irq = -1;
+               }
+       }
+
+       rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
+               THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto out;
+       }
+       pdata->rtc = rtc;
+       platform_set_drvdata(pdev, pdata);
+       ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+       if (ret) {
+               goto out;
+       }
+       return 0;
+ out:
+       if (pdata->rtc) {
+               rtc_device_unregister(pdata->rtc);
+       }
+       if (pdata->irq >= 0) {
+               free_irq(pdata->irq, pdev);
+       }
+       if (ds1511_base) {
+               iounmap(ds1511_base);
+               ds1511_base = NULL;
+       }
+       if (pdata->baseaddr) {
+               release_mem_region(pdata->baseaddr, pdata->size);
+       }
+
+       kfree(pdata);
+       return ret;
+}
+
+ static int __devexit
+ds1511_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+       sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
+       rtc_device_unregister(pdata->rtc);
+       pdata->rtc = NULL;
+       if (pdata->irq >= 0) {
+               /*
+                * disable the alarm interrupt
+                */
+               rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
+               rtc_read(RTC_CMD1);
+               free_irq(pdata->irq, pdev);
+       }
+       iounmap(pdata->ioaddr);
+       ds1511_base = NULL;
+       release_mem_region(pdata->baseaddr, pdata->size);
+       kfree(pdata);
+       return 0;
+}
+
+static struct platform_driver ds1511_rtc_driver = {
+       .probe          = ds1511_rtc_probe,
+       .remove         = __devexit_p(ds1511_rtc_remove),
+       .driver         = {
+               .name   = "ds1511",
+               .owner  = THIS_MODULE,
+       },
+};
+
+ static int __init
+ds1511_rtc_init(void)
+{
+       return platform_driver_register(&ds1511_rtc_driver);
+}
+
+ static void __exit
+ds1511_rtc_exit(void)
+{
+       return platform_driver_unregister(&ds1511_rtc_driver);
+}
+
+module_init(ds1511_rtc_init);
+module_exit(ds1511_rtc_exit);
+
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index c973ba9..8b39970 100644 (file)
@@ -163,27 +163,17 @@ static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem)
 
 static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
 {
-       unsigned char addr[1];
-       struct i2c_msg msgs[2] = {
-               {
-                       .addr = client->addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = addr,
-               }, {
-                       .addr = client->addr,
-                       .flags = I2C_M_NOSTART,
-                       .len = mem->nr,
-                       .buf = mem->data,
-               }
-       };
+       unsigned char buf[9];
+       int ret;
 
-       if (mem->loc < 8)
+       if (mem->loc < 8 || mem->nr > 8)
                return -EINVAL;
 
-       addr[0] = mem->loc;
+       buf[0] = mem->loc;
+       memcpy(buf + 1, mem->data, mem->nr);
 
-       return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+       ret = i2c_master_send(client, buf, mem->nr + 1);
+       return ret == mem->nr + 1 ? 0 : -EIO;
 }
 
 static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
new file mode 100644 (file)
index 0000000..a64626a
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Driver for Epson RTC-9701JE
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on rtc-max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#define RSECCNT        0x00    /* Second Counter */
+#define RMINCNT        0x01    /* Minute Counter */
+#define RHRCNT 0x02    /* Hour Counter */
+#define RWKCNT 0x03    /* Week Counter */
+#define RDAYCNT        0x04    /* Day Counter */
+#define RMONCNT        0x05    /* Month Counter */
+#define RYRCNT 0x06    /* Year Counter */
+#define R100CNT        0x07    /* Y100 Counter */
+#define RMINAR 0x08    /* Minute Alarm */
+#define RHRAR  0x09    /* Hour Alarm */
+#define RWKAR  0x0a    /* Week/Day Alarm */
+#define RTIMCNT        0x0c    /* Interval Timer */
+#define REXT   0x0d    /* Extension Register */
+#define RFLAG  0x0e    /* RTC Flag Register */
+#define RCR    0x0f    /* RTC Control Register */
+
+static int write_reg(struct device *dev, int address, unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       buf[0] = address & 0x7f;
+       buf[1] = data;
+
+       return spi_write(spi, buf, ARRAY_SIZE(buf));
+}
+
+static int read_regs(struct device *dev, unsigned char *regs, int no_regs)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       u8 txbuf[1], rxbuf[1];
+       int k, ret;
+
+       ret = 0;
+
+       for (k = 0; ret == 0 && k < no_regs; k++) {
+               txbuf[0] = 0x80 | regs[k];
+               ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+               regs[k] = rxbuf[0];
+       }
+
+       return ret;
+}
+
+static int r9701_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+       unsigned long time;
+       int ret;
+       unsigned char buf[] = { RSECCNT, RMINCNT, RHRCNT,
+                               RDAYCNT, RMONCNT, RYRCNT };
+
+       ret = read_regs(dev, buf, ARRAY_SIZE(buf));
+       if (ret)
+               return ret;
+
+       memset(dt, 0, sizeof(*dt));
+
+       dt->tm_sec = BCD2BIN(buf[0]); /* RSECCNT */
+       dt->tm_min = BCD2BIN(buf[1]); /* RMINCNT */
+       dt->tm_hour = BCD2BIN(buf[2]); /* RHRCNT */
+
+       dt->tm_mday = BCD2BIN(buf[3]); /* RDAYCNT */
+       dt->tm_mon = BCD2BIN(buf[4]) - 1; /* RMONCNT */
+       dt->tm_year = BCD2BIN(buf[5]) + 100; /* RYRCNT */
+
+       /* the rtc device may contain illegal values on power up
+        * according to the data sheet. make sure they are valid.
+        */
+
+       return rtc_valid_tm(dt);
+}
+
+static int r9701_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+       int ret, year;
+
+       year = dt->tm_year + 1900;
+       if (year >= 2100 || year < 2000)
+               return -EINVAL;
+
+       ret = write_reg(dev, RHRCNT, BIN2BCD(dt->tm_hour));
+       ret = ret ? ret : write_reg(dev, RMINCNT, BIN2BCD(dt->tm_min));
+       ret = ret ? ret : write_reg(dev, RSECCNT, BIN2BCD(dt->tm_sec));
+       ret = ret ? ret : write_reg(dev, RDAYCNT, BIN2BCD(dt->tm_mday));
+       ret = ret ? ret : write_reg(dev, RMONCNT, BIN2BCD(dt->tm_mon + 1));
+       ret = ret ? ret : write_reg(dev, RYRCNT, BIN2BCD(dt->tm_year - 100));
+       ret = ret ? ret : write_reg(dev, RWKCNT, 1 << dt->tm_wday);
+
+       return ret;
+}
+
+static const struct rtc_class_ops r9701_rtc_ops = {
+       .read_time      = r9701_get_datetime,
+       .set_time       = r9701_set_datetime,
+};
+
+static int __devinit r9701_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char tmp;
+       int res;
+
+       rtc = rtc_device_register("r9701",
+                               &spi->dev, &r9701_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       dev_set_drvdata(&spi->dev, rtc);
+
+       tmp = R100CNT;
+       res = read_regs(&spi->dev, &tmp, 1);
+       if (res || tmp != 0x20) {
+               rtc_device_unregister(rtc);
+               return res;
+       }
+
+       return 0;
+}
+
+static int __devexit r9701_remove(struct spi_device *spi)
+{
+       struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
+
+       rtc_device_unregister(rtc);
+       return 0;
+}
+
+static struct spi_driver r9701_driver = {
+       .driver = {
+               .name   = "rtc-r9701",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = r9701_probe,
+       .remove = __devexit_p(r9701_remove),
+};
+
+static __init int r9701_init(void)
+{
+       return spi_register_driver(&r9701_driver);
+}
+module_init(r9701_init);
+
+static __exit void r9701_exit(void)
+{
+       spi_unregister_driver(&r9701_driver);
+}
+module_exit(r9701_exit);
+
+MODULE_DESCRIPTION("r9701 spi RTC driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
index e2041b4..86766f1 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/rtc.h>
 #include <linux/bcd.h>
 #include <linux/clk.h>
+#include <linux/log2.h>
 
 #include <asm/hardware.h>
 #include <asm/uaccess.h>
@@ -309,9 +310,7 @@ static int s3c_rtc_ioctl(struct device *dev,
                break;
 
        case RTC_IRQP_SET:
-               /* check for power of 2 */
-
-               if ((arg & (arg-1)) != 0 || arg < 1) {
+               if (!is_power_of_2(arg)) {
                        ret = -EINVAL;
                        goto exit;
                }
index 2eb3852..ee253cc 100644 (file)
@@ -357,23 +357,15 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       if (pdev->dev.power.power_state.event != state.event) {
-               if (state.event == PM_EVENT_SUSPEND &&
-                   device_may_wakeup(&pdev->dev))
-                       enable_irq_wake(IRQ_RTCAlrm);
-
-               pdev->dev.power.power_state = state;
-       }
+       if (device_may_wakeup(&pdev->dev))
+               enable_irq_wake(IRQ_RTCAlrm);
        return 0;
 }
 
 static int sa1100_rtc_resume(struct platform_device *pdev)
 {
-       if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
-               if (device_may_wakeup(&pdev->dev))
-                       disable_irq_wake(IRQ_RTCAlrm);
-               pdev->dev.power.power_state = PMSG_ON;
-       }
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(IRQ_RTCAlrm);
        return 0;
 }
 #else
index 2ae0e83..4d27ccc 100644 (file)
 
 /* device attributes */
 
+/*
+ * NOTE:  RTC times displayed in sysfs use the RTC's timezone.  That's
+ * ideally UTC.  However, PCs that also boot to MS-Windows normally use
+ * the local time and change to match daylight savings time.  That affects
+ * attributes including date, time, since_epoch, and wakealarm.
+ */
+
 static ssize_t
 rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
                char *buf)
@@ -113,13 +120,13 @@ rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
        unsigned long alarm;
        struct rtc_wkalrm alm;
 
-       /* Don't show disabled alarms; but the RTC could leave the
-        * alarm enabled after it's already triggered.  Alarms are
-        * conceptually one-shot, even though some common hardware
-        * (PCs) doesn't actually work that way.
+       /* Don't show disabled alarms.  For uniformity, RTC alarms are
+        * conceptually one-shot, even though some common RTCs (on PCs)
+        * don't actually work that way.
         *
-        * REVISIT maybe we should require RTC implementations to
-        * disable the RTC alarm after it triggers, for uniformity.
+        * NOTE: RTC implementations where the alarm doesn't match an
+        * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
+        * alarms after they trigger, to ensure one-shot semantics.
         */
        retval = rtc_read_alarm(to_rtc_device(dev), &alm);
        if (retval == 0 && alm.enabled) {
index 19343f9..291ff62 100644 (file)
@@ -422,7 +422,7 @@ void s390_adjust_jiffies(void)
 /*
  * calibrate the delay loop
  */
-void __init calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        s390_adjust_jiffies();
        /* Print the good old Bogomips line .. */
index 23f27c9..5ac3a3e 100644 (file)
@@ -46,8 +46,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
     struct Scsi_Host *instance = cmd->device->host;
 
     /* don't allow DMA if the physical address is bad */
-    if (addr & A2091_XFER_MASK ||
-       (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    if (addr & A2091_XFER_MASK)
     {
        HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
            & ~0x1ff;
index d7255c8..3aeec96 100644 (file)
@@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
      * end of a physical memory chunk, then allocate a bounce
      * buffer
      */
-    if (addr & A3000_XFER_MASK ||
-       (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    if (addr & A3000_XFER_MASK)
     {
        HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
            & ~0x1ff;
index 3bfd929..93984c9 100644 (file)
@@ -6472,7 +6472,7 @@ do_aic7xxx_isr(int irq, void *dev_id)
   unsigned long cpu_flags;
   struct aic7xxx_host *p;
   
-  p = (struct aic7xxx_host *)dev_id;
+  p = dev_id;
   if(!p)
     return IRQ_NONE;
   spin_lock_irqsave(p->host->host_lock, cpu_flags);
index 37741e9..91f8522 100644 (file)
@@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
     static int scsi_alloc_out_of_range = 0;
 
     /* use bounce buffer if the physical address is bad */
-    if (addr & HDATA(cmd->device->host)->dma_xfer_mask ||
-       (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    if (addr & HDATA(cmd->device->host)->dma_xfer_mask)
     {
        HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
            & ~0x1ff;
index d63f11e..bd62131 100644 (file)
@@ -539,9 +539,9 @@ out:
                srp_iu_put(iue);
 }
 
-static irqreturn_t ibmvstgt_interrupt(int irq, void *data)
+static irqreturn_t ibmvstgt_interrupt(int dummy, void *data)
 {
-       struct srp_target *target = (struct srp_target *) data;
+       struct srp_target *target = data;
        struct vio_port *vport = target_to_port(target);
 
        vio_disable_interrupts(vport->dma_dev);
index 672c759..77a62a1 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/uio.h>
index 4fa7927..6a44fb1 100644 (file)
@@ -877,15 +877,15 @@ config SERIAL_SUNHV
          systems.  Say Y if you want to be able to use this device.
 
 config SERIAL_IP22_ZILOG
-       tristate "IP22 Zilog8530 serial support"
-       depends on SGI_IP22
+       tristate "SGI Zilog8530 serial support"
+       depends on SGI_HAS_ZILOG
        select SERIAL_CORE
        help
-         This driver supports the Zilog8530 serial ports found on SGI IP22
+         This driver supports the Zilog8530 serial ports found on SGI
          systems.  Say Y or M if you want to be able to these serial ports.
 
 config SERIAL_IP22_ZILOG_CONSOLE
-       bool "Console on IP22 Zilog8530 serial port"
+       bool "Console on SGI Zilog8530 serial port"
        depends on SERIAL_IP22_ZILOG=y
        select SERIAL_CORE_CONSOLE
 
@@ -1318,4 +1318,19 @@ config SERIAL_QE
          This driver supports the QE serial ports on Freescale embedded
          PowerPC that contain a QUICC Engine.
 
+config SERIAL_SC26XX
+       tristate "SC2681/SC2692 serial port support"
+       depends on SNI_RM
+       select SERIAL_CORE
+       help
+         This is a driver for the onboard serial ports of
+         older RM400 machines.
+
+config SERIAL_SC26XX_CONSOLE
+       bool "Console on SC2681/SC2692 serial port"
+       depends on SERIAL_SC26XX
+       select SERIAL_CORE_CONSOLE
+       help
+         Support for Console on SC2681/SC2692 serial ports.
+
 endmenu
index 2dd41b4..640cfe4 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
 obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
 obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
 obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
 obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
index b5e4478..236af9d 100644 (file)
@@ -380,7 +380,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
 static irqreturn_t cpm_uart_int(int irq, void *data)
 {
        u8 events;
-       struct uart_port *port = (struct uart_port *)data;
+       struct uart_port *port = data;
        struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
        smc_t __iomem *smcp = pinfo->smcp;
        scc_t __iomem *sccp = pinfo->sccp;
index d31721f..bbae5a2 100644 (file)
@@ -324,7 +324,7 @@ static inline void check_modem_status(struct dz_port *dport)
  */
 static irqreturn_t dz_interrupt(int irq, void *dev)
 {
-       struct dz_port *dport = (struct dz_port *)dev;
+       struct dz_port *dport = dev;
        unsigned short status;
 
        /* get the reason why we just got an irq */
index dc19671..56af1f5 100644 (file)
@@ -308,7 +308,7 @@ static void imx_start_tx(struct uart_port *port)
 
 static irqreturn_t imx_rtsint(int irq, void *dev_id)
 {
-       struct imx_port *sport = (struct imx_port *)dev_id;
+       struct imx_port *sport = dev_id;
        unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
        unsigned long flags;
 
@@ -324,7 +324,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id)
 
 static irqreturn_t imx_txint(int irq, void *dev_id)
 {
-       struct imx_port *sport = (struct imx_port *)dev_id;
+       struct imx_port *sport = dev_id;
        struct circ_buf *xmit = &sport->port.info->xmit;
        unsigned long flags;
 
diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c
new file mode 100644 (file)
index 0000000..a350b6d
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
+ *
+ * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#define SC26XX_MAJOR         204
+#define SC26XX_MINOR_START   205
+#define SC26XX_NR            2
+
+struct uart_sc26xx_port {
+       struct uart_port      port[2];
+       u8     dsr_mask[2];
+       u8     cts_mask[2];
+       u8     dcd_mask[2];
+       u8     ri_mask[2];
+       u8     dtr_mask[2];
+       u8     rts_mask[2];
+       u8     imr;
+};
+
+/* register common to both ports */
+#define RD_ISR      0x14
+#define RD_IPR      0x34
+
+#define WR_ACR      0x10
+#define WR_IMR      0x14
+#define WR_OPCR     0x34
+#define WR_OPR_SET  0x38
+#define WR_OPR_CLR  0x3C
+
+/* access common register */
+#define READ_SC(p, r)        readb((p)->membase + RD_##r)
+#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
+
+/* register per port */
+#define RD_PORT_MRx 0x00
+#define RD_PORT_SR  0x04
+#define RD_PORT_RHR 0x0c
+
+#define WR_PORT_MRx 0x00
+#define WR_PORT_CSR 0x04
+#define WR_PORT_CR  0x08
+#define WR_PORT_THR 0x0c
+
+/* SR bits */
+#define SR_BREAK    (1 << 7)
+#define SR_FRAME    (1 << 6)
+#define SR_PARITY   (1 << 5)
+#define SR_OVERRUN  (1 << 4)
+#define SR_TXRDY    (1 << 2)
+#define SR_RXRDY    (1 << 0)
+
+#define CR_RES_MR   (1 << 4)
+#define CR_RES_RX   (2 << 4)
+#define CR_RES_TX   (3 << 4)
+#define CR_STRT_BRK (6 << 4)
+#define CR_STOP_BRK (7 << 4)
+#define CR_DIS_TX   (1 << 3)
+#define CR_ENA_TX   (1 << 2)
+#define CR_DIS_RX   (1 << 1)
+#define CR_ENA_RX   (1 << 0)
+
+/* ISR bits */
+#define ISR_RXRDYB  (1 << 5)
+#define ISR_TXRDYB  (1 << 4)
+#define ISR_RXRDYA  (1 << 1)
+#define ISR_TXRDYA  (1 << 0)
+
+/* IMR bits */
+#define IMR_RXRDY   (1 << 1)
+#define IMR_TXRDY   (1 << 0)
+
+/* access port register */
+static inline u8 read_sc_port(struct uart_port *p, u8 reg)
+{
+       return readb(p->membase + p->line * 0x20 + reg);
+}
+
+static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
+{
+       writeb(val, p->membase + p->line * 0x20 + reg);
+}
+
+#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
+#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
+
+static void sc26xx_enable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr |= mask << (line * 4);
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static void sc26xx_disable_irq(struct uart_port *port, int mask)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       up->imr &= ~(mask << (line * 4));
+       WRITE_SC(port, IMR, up->imr);
+}
+
+static struct tty_struct *receive_chars(struct uart_port *port)
+{
+       struct tty_struct *tty = NULL;
+       int limit = 10000;
+       unsigned char ch;
+       char flag;
+       u8 status;
+
+       if (port->info != NULL)         /* Unopened serial console */
+               tty = port->info->tty;
+
+       while (limit-- > 0) {
+               status = READ_SC_PORT(port, SR);
+               if (!(status & SR_RXRDY))
+                       break;
+               ch = READ_SC_PORT(port, RHR);
+
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (unlikely(status & (SR_BREAK | SR_FRAME |
+                                      SR_PARITY | SR_OVERRUN))) {
+                       if (status & SR_BREAK) {
+                               status &= ~(SR_PARITY | SR_FRAME);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       } else if (status & SR_PARITY)
+                               port->icount.parity++;
+                       else if (status & SR_FRAME)
+                               port->icount.frame++;
+                       if (status & SR_OVERRUN)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+                       if (status & SR_BREAK)
+                               flag = TTY_BREAK;
+                       else if (status & SR_PARITY)
+                               flag = TTY_PARITY;
+                       else if (status & SR_FRAME)
+                               flag = TTY_FRAME;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+
+               if (status & port->ignore_status_mask)
+                       continue;
+
+               tty_insert_flip_char(tty, ch, flag);
+       }
+       return tty;
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+       struct circ_buf *xmit;
+
+       if (!port->info)
+               return;
+
+       xmit = &port->info->xmit;
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               sc26xx_disable_irq(port, IMR_TXRDY);
+               return;
+       }
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
+                       break;
+
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+}
+
+static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
+{
+       struct uart_sc26xx_port *up = dev_id;
+       struct tty_struct *tty;
+       unsigned long flags;
+       u8 isr;
+
+       spin_lock_irqsave(&up->port[0].lock, flags);
+
+       tty = NULL;
+       isr = READ_SC(&up->port[0], ISR);
+       if (isr & ISR_TXRDYA)
+           transmit_chars(&up->port[0]);
+       if (isr & ISR_RXRDYA)
+           tty = receive_chars(&up->port[0]);
+
+       spin_unlock(&up->port[0].lock);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       spin_lock(&up->port[1].lock);
+
+       tty = NULL;
+       if (isr & ISR_TXRDYB)
+           transmit_chars(&up->port[1]);
+       if (isr & ISR_RXRDYB)
+           tty = receive_chars(&up->port[1]);
+
+       spin_unlock_irqrestore(&up->port[1].lock, flags);
+
+       if (tty)
+               tty_flip_buffer_push(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int sc26xx_tx_empty(struct uart_port *port)
+{
+       return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+
+       if (up->dtr_mask[line]) {
+               if (mctrl & TIOCM_DTR)
+                       WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
+       }
+       if (up->rts_mask[line]) {
+               if (mctrl & TIOCM_RTS)
+                       WRITE_SC(port, OPR_SET, up->rts_mask[line]);
+               else
+                       WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
+       }
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int sc26xx_get_mctrl(struct uart_port *port)
+{
+       struct uart_sc26xx_port *up;
+       int line = port->line;
+       unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+       u8 ipr;
+
+       port -= line;
+       up = container_of(port, struct uart_sc26xx_port, port[0]);
+       ipr = READ_SC(port, IPR) ^ 0xff;
+
+       if (up->dsr_mask[line]) {
+               mctrl &= ~TIOCM_DSR;
+               mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
+       }
+       if (up->cts_mask[line]) {
+               mctrl &= ~TIOCM_CTS;
+               mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
+       }
+       if (up->dcd_mask[line]) {
+               mctrl &= ~TIOCM_CAR;
+               mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
+       }
+       if (up->ri_mask[line]) {
+               mctrl &= ~TIOCM_RNG;
+               mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
+       }
+       return mctrl;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_tx(struct uart_port *port)
+{
+       return;
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_start_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->info->xmit;
+
+       while (!uart_circ_empty(xmit)) {
+               if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
+                       sc26xx_enable_irq(port, IMR_TXRDY);
+                       break;
+               }
+               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_stop_rx(struct uart_port *port)
+{
+}
+
+/* port->lock held by caller.  */
+static void sc26xx_enable_ms(struct uart_port *port)
+{
+}
+
+/* port->lock is not held.  */
+static void sc26xx_break_ctl(struct uart_port *port, int break_state)
+{
+       if (break_state == -1)
+               WRITE_SC_PORT(port, CR, CR_STRT_BRK);
+       else
+               WRITE_SC_PORT(port, CR, CR_STOP_BRK);
+}
+
+/* port->lock is not held.  */
+static int sc26xx_startup(struct uart_port *port)
+{
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+       WRITE_SC(port, OPCR, 0);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       /* start rx/tx */
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+
+       /* enable irqs */
+       sc26xx_enable_irq(port, IMR_RXRDY);
+       return 0;
+}
+
+/* port->lock is not held.  */
+static void sc26xx_shutdown(struct uart_port *port)
+{
+       /* disable interrupst */
+       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+       /* stop tx/rx */
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+}
+
+/* port->lock is not held.  */
+static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+{
+       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       unsigned int quot = uart_get_divisor(port, baud);
+       unsigned int iflag, cflag;
+       unsigned long flags;
+       u8 mr1, mr2, csr;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
+
+       iflag = termios->c_iflag;
+       cflag = termios->c_cflag;
+
+       port->read_status_mask = SR_OVERRUN;
+       if (iflag & INPCK)
+               port->read_status_mask |= SR_PARITY | SR_FRAME;
+       if (iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= SR_BREAK;
+
+       port->ignore_status_mask = 0;
+       if (iflag & IGNBRK)
+               port->ignore_status_mask |= SR_BREAK;
+       if ((cflag & CREAD) == 0)
+               port->ignore_status_mask |= SR_BREAK | SR_FRAME |
+                                           SR_PARITY | SR_OVERRUN;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               mr1 = 0x00;
+               break;
+       case CS6:
+               mr1 = 0x01;
+               break;
+       case CS7:
+               mr1 = 0x02;
+               break;
+       default:
+       case CS8:
+               mr1 = 0x03;
+               break;
+       }
+       mr2 = 0x07;
+       if (cflag & CSTOPB)
+               mr2 = 0x0f;
+       if (cflag & PARENB) {
+               if (cflag & PARODD)
+                       mr1 |= (1 << 2);
+       } else
+               mr1 |= (2 << 3);
+
+       switch (baud) {
+       case 50:
+               csr = 0x00;
+               break;
+       case 110:
+               csr = 0x11;
+               break;
+       case 134:
+               csr = 0x22;
+               break;
+       case 200:
+               csr = 0x33;
+               break;
+       case 300:
+               csr = 0x44;
+               break;
+       case 600:
+               csr = 0x55;
+               break;
+       case 1200:
+               csr = 0x66;
+               break;
+       case 2400:
+               csr = 0x88;
+               break;
+       case 4800:
+               csr = 0x99;
+               break;
+       default:
+       case 9600:
+               csr = 0xbb;
+               break;
+       case 19200:
+               csr = 0xcc;
+               break;
+       }
+
+       WRITE_SC_PORT(port, CR, CR_RES_MR);
+       WRITE_SC_PORT(port, MRx, mr1);
+       WRITE_SC_PORT(port, MRx, mr2);
+
+       WRITE_SC(port, ACR, 0x80);
+       WRITE_SC_PORT(port, CSR, csr);
+
+       /* reset tx and rx */
+       WRITE_SC_PORT(port, CR, CR_RES_RX);
+       WRITE_SC_PORT(port, CR, CR_RES_TX);
+
+       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
+       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
+               udelay(2);
+
+       /* XXX */
+       uart_update_timeout(port, cflag,
+                           (port->uartclk / (16 * quot)));
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sc26xx_type(struct uart_port *port)
+{
+       return "SC26XX";
+}
+
+static void sc26xx_release_port(struct uart_port *port)
+{
+}
+
+static int sc26xx_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void sc26xx_config_port(struct uart_port *port, int flags)
+{
+}
+
+static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return -EINVAL;
+}
+
+static struct uart_ops sc26xx_ops = {
+       .tx_empty       = sc26xx_tx_empty,
+       .set_mctrl      = sc26xx_set_mctrl,
+       .get_mctrl      = sc26xx_get_mctrl,
+       .stop_tx        = sc26xx_stop_tx,
+       .start_tx       = sc26xx_start_tx,
+       .stop_rx        = sc26xx_stop_rx,
+       .enable_ms      = sc26xx_enable_ms,
+       .break_ctl      = sc26xx_break_ctl,
+       .startup        = sc26xx_startup,
+       .shutdown       = sc26xx_shutdown,
+       .set_termios    = sc26xx_set_termios,
+       .type           = sc26xx_type,
+       .release_port   = sc26xx_release_port,
+       .request_port   = sc26xx_request_port,
+       .config_port    = sc26xx_config_port,
+       .verify_port    = sc26xx_verify_port,
+};
+
+static struct uart_port *sc26xx_port;
+
+#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
+static void sc26xx_console_putchar(struct uart_port *port, char c)
+{
+       unsigned long flags;
+       int limit = 1000000;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (limit-- > 0) {
+               if (READ_SC_PORT(port, SR) & SR_TXRDY) {
+                       WRITE_SC_PORT(port, THR, c);
+                       break;
+               }
+               udelay(2);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
+{
+       struct uart_port *port = sc26xx_port;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (*s == '\n')
+                       sc26xx_console_putchar(port, '\r');
+               sc26xx_console_putchar(port, *s++);
+       }
+}
+
+static int __init sc26xx_console_setup(struct console *con, char *options)
+{
+       struct uart_port *port = sc26xx_port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (port->type != PORT_SC26XX)
+               return -1;
+
+       printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, con, baud, parity, bits, flow);
+}
+
+static struct uart_driver sc26xx_reg;
+static struct console sc26xx_console = {
+       .name   =       "ttySC",
+       .write  =       sc26xx_console_write,
+       .device =       uart_console_device,
+       .setup  =       sc26xx_console_setup,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+       .data   =       &sc26xx_reg,
+};
+#define SC26XX_CONSOLE   &sc26xx_console
+#else
+#define SC26XX_CONSOLE   NULL
+#endif
+
+static struct uart_driver sc26xx_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "SC26xx",
+       .dev_name               = "ttySC",
+       .major                  = SC26XX_MAJOR,
+       .minor                  = SC26XX_MINOR_START,
+       .nr                     = SC26XX_NR,
+       .cons                   = SC26XX_CONSOLE,
+};
+
+static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
+{
+       unsigned int bit = (flags >> bitpos) & 15;
+
+       return bit ? (1 << (bit - 1)) : 0;
+}
+
+static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up,
+                                       int line, unsigned int data)
+{
+       up->dtr_mask[line] = sc26xx_flags2mask(data,  0);
+       up->rts_mask[line] = sc26xx_flags2mask(data,  4);
+       up->dsr_mask[line] = sc26xx_flags2mask(data,  8);
+       up->cts_mask[line] = sc26xx_flags2mask(data, 12);
+       up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
+       up->ri_mask[line]  = sc26xx_flags2mask(data, 20);
+}
+
+static int __devinit sc26xx_probe(struct platform_device *dev)
+{
+       struct resource *res;
+       struct uart_sc26xx_port *up;
+       unsigned int *sc26xx_data = dev->dev.platform_data;
+       int err;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       up = kzalloc(sizeof *up, GFP_KERNEL);
+       if (unlikely(!up))
+               return -ENOMEM;
+
+       up->port[0].line = 0;
+       up->port[0].ops = &sc26xx_ops;
+       up->port[0].type = PORT_SC26XX;
+       up->port[0].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[0].mapbase = res->start;
+       up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
+       up->port[0].iotype = UPIO_MEM;
+       up->port[0].irq = platform_get_irq(dev, 0);
+
+       up->port[0].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 0, sc26xx_data[0]);
+
+       sc26xx_port = &up->port[0];
+
+       up->port[1].line = 1;
+       up->port[1].ops = &sc26xx_ops;
+       up->port[1].type = PORT_SC26XX;
+       up->port[1].uartclk = (29491200 / 16); /* arbitrary */
+
+       up->port[1].mapbase = up->port[0].mapbase;
+       up->port[1].membase = up->port[0].membase;
+       up->port[1].iotype = UPIO_MEM;
+       up->port[1].irq = up->port[0].irq;
+
+       up->port[1].dev = &dev->dev;
+
+       sc26xx_init_masks(up, 1, sc26xx_data[1]);
+
+       err = uart_register_driver(&sc26xx_reg);
+       if (err)
+               goto out_free_port;
+
+       sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
+       if (err)
+               goto out_unregister_driver;
+
+       err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
+       if (err)
+               goto out_remove_port0;
+
+       err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
+       if (err)
+               goto out_remove_ports;
+
+       dev_set_drvdata(&dev->dev, up);
+       return 0;
+
+out_remove_ports:
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+out_remove_port0:
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+
+out_unregister_driver:
+       uart_unregister_driver(&sc26xx_reg);
+
+out_free_port:
+       kfree(up);
+       sc26xx_port = NULL;
+       return err;
+}
+
+
+static int __exit sc26xx_driver_remove(struct platform_device *dev)
+{
+       struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
+
+       free_irq(up->port[0].irq, up);
+
+       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
+       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
+
+       uart_unregister_driver(&sc26xx_reg);
+
+       kfree(up);
+       sc26xx_port = NULL;
+
+       dev_set_drvdata(&dev->dev, NULL);
+       return 0;
+}
+
+static struct platform_driver sc26xx_driver = {
+       .probe  = sc26xx_probe,
+       .remove = __devexit_p(sc26xx_driver_remove),
+       .driver = {
+               .name   = "SC26xx",
+       },
+};
+
+static int __init sc26xx_init(void)
+{
+       return platform_driver_register(&sc26xx_driver);
+}
+
+static void __exit sc26xx_exit(void)
+{
+       platform_driver_unregister(&sc26xx_driver);
+}
+
+module_init(sc26xx_init);
+module_exit(sc26xx_exit);
+
+
+MODULE_AUTHOR("Thomas Bogendörfer");
+MODULE_DESCRIPTION("SC681/SC2692 serial driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
index 8094340..bacf68d 100644 (file)
@@ -142,7 +142,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
 
 static irqreturn_t ulite_isr(int irq, void *dev_id)
 {
-       struct uart_port *port = (struct uart_port *)dev_id;
+       struct uart_port *port = dev_id;
        int busy;
 
        do {
index aaaea81..d810789 100644 (file)
@@ -144,10 +144,10 @@ config SPI_OMAP_UWIRE
          This hooks up to the MicroWire controller on OMAP1 chips.
 
 config SPI_OMAP24XX
-       tristate "McSPI driver for OMAP24xx"
-       depends on SPI_MASTER && ARCH_OMAP24XX
+       tristate "McSPI driver for OMAP24xx/OMAP34xx"
+       depends on SPI_MASTER && (ARCH_OMAP24XX || ARCH_OMAP34XX)
        help
-         SPI master controller for OMAP24xx Multichannel SPI
+         SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
          (McSPI) modules.
 
 config SPI_PXA2XX
@@ -176,6 +176,13 @@ config SPI_S3C24XX_GPIO
          the inbuilt hardware cannot provide the transfer mode, or
          where the board is using non hardware connected pins.
 
+config SPI_SH_SCI
+       tristate "SuperH SCI SPI controller"
+       depends on SPI_MASTER && SUPERH
+       select SPI_BITBANG
+       help
+         SPI driver for SuperH SCI blocks.
+
 config SPI_TXX9
        tristate "Toshiba TXx9 SPI controller"
        depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
index 41fbac4..7fca043 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO)                += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx.o
 obj-$(CONFIG_SPI_TXX9)                 += spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
+obj-$(CONFIG_SPI_SH_SCI)               += spi_sh_sci.o
 #      ... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
index ff10808..293b7ca 100644 (file)
@@ -51,7 +51,9 @@ struct atmel_spi {
        u8                      stopping;
        struct list_head        queue;
        struct spi_transfer     *current_transfer;
-       unsigned long           remaining_bytes;
+       unsigned long           current_remaining_bytes;
+       struct spi_transfer     *next_transfer;
+       unsigned long           next_remaining_bytes;
 
        void                    *buffer;
        dma_addr_t              buffer_dma;
@@ -121,6 +123,48 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
                gpio_set_value(gpio, !active);
 }
 
+static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+                                       struct spi_transfer *xfer)
+{
+       return msg->transfers.prev == &xfer->transfer_list;
+}
+
+static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+{
+       return xfer->delay_usecs == 0 && !xfer->cs_change;
+}
+
+static void atmel_spi_next_xfer_data(struct spi_master *master,
+                               struct spi_transfer *xfer,
+                               dma_addr_t *tx_dma,
+                               dma_addr_t *rx_dma,
+                               u32 *plen)
+{
+       struct atmel_spi        *as = spi_master_get_devdata(master);
+       u32                     len = *plen;
+
+       /* use scratch buffer only when rx or tx data is unspecified */
+       if (xfer->rx_buf)
+               *rx_dma = xfer->rx_dma + xfer->len - len;
+       else {
+               *rx_dma = as->buffer_dma;
+               if (len > BUFFER_SIZE)
+                       len = BUFFER_SIZE;
+       }
+       if (xfer->tx_buf)
+               *tx_dma = xfer->tx_dma + xfer->len - len;
+       else {
+               *tx_dma = as->buffer_dma;
+               if (len > BUFFER_SIZE)
+                       len = BUFFER_SIZE;
+               memset(as->buffer, 0, len);
+               dma_sync_single_for_device(&as->pdev->dev,
+                               as->buffer_dma, len, DMA_TO_DEVICE);
+       }
+
+       *plen = len;
+}
+
 /*
  * Submit next transfer for DMA.
  * lock is held, spi irq is blocked
@@ -130,53 +174,78 @@ static void atmel_spi_next_xfer(struct spi_master *master,
 {
        struct atmel_spi        *as = spi_master_get_devdata(master);
        struct spi_transfer     *xfer;
-       u32                     len;
+       u32                     len, remaining, total;
        dma_addr_t              tx_dma, rx_dma;
 
-       xfer = as->current_transfer;
-       if (!xfer || as->remaining_bytes == 0) {
-               if (xfer)
-                       xfer = list_entry(xfer->transfer_list.next,
-                                       struct spi_transfer, transfer_list);
-               else
-                       xfer = list_entry(msg->transfers.next,
-                                       struct spi_transfer, transfer_list);
-               as->remaining_bytes = xfer->len;
-               as->current_transfer = xfer;
-       }
+       if (!as->current_transfer)
+               xfer = list_entry(msg->transfers.next,
+                               struct spi_transfer, transfer_list);
+       else if (!as->next_transfer)
+               xfer = list_entry(as->current_transfer->transfer_list.next,
+                               struct spi_transfer, transfer_list);
+       else
+               xfer = NULL;
 
-       len = as->remaining_bytes;
+       if (xfer) {
+               len = xfer->len;
+               atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+               remaining = xfer->len - len;
 
-       tx_dma = xfer->tx_dma + xfer->len - len;
-       rx_dma = xfer->rx_dma + xfer->len - len;
+               spi_writel(as, RPR, rx_dma);
+               spi_writel(as, TPR, tx_dma);
 
-       /* use scratch buffer only when rx or tx data is unspecified */
-       if (!xfer->rx_buf) {
-               rx_dma = as->buffer_dma;
-               if (len > BUFFER_SIZE)
-                       len = BUFFER_SIZE;
-       }
-       if (!xfer->tx_buf) {
-               tx_dma = as->buffer_dma;
-               if (len > BUFFER_SIZE)
-                       len = BUFFER_SIZE;
-               memset(as->buffer, 0, len);
-               dma_sync_single_for_device(&as->pdev->dev,
-                               as->buffer_dma, len, DMA_TO_DEVICE);
+               if (msg->spi->bits_per_word > 8)
+                       len >>= 1;
+               spi_writel(as, RCR, len);
+               spi_writel(as, TCR, len);
+
+               dev_dbg(&msg->spi->dev,
+                       "  start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+                       xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+                       xfer->rx_buf, xfer->rx_dma);
+       } else {
+               xfer = as->next_transfer;
+               remaining = as->next_remaining_bytes;
        }
 
-       spi_writel(as, RPR, rx_dma);
-       spi_writel(as, TPR, tx_dma);
+       as->current_transfer = xfer;
+       as->current_remaining_bytes = remaining;
 
-       as->remaining_bytes -= len;
-       if (msg->spi->bits_per_word > 8)
-               len >>= 1;
+       if (remaining > 0)
+               len = remaining;
+       else if (!atmel_spi_xfer_is_last(msg, xfer)
+                       && atmel_spi_xfer_can_be_chained(xfer)) {
+               xfer = list_entry(xfer->transfer_list.next,
+                               struct spi_transfer, transfer_list);
+               len = xfer->len;
+       } else
+               xfer = NULL;
 
-       /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
-        * mechanism might help avoid the IRQ latency between transfers
-        * (and improve the nCS0 errata handling on at91rm9200 chips)
-        *
-        * We're also waiting for ENDRX before we start the next
+       as->next_transfer = xfer;
+
+       if (xfer) {
+               total = len;
+               atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+               as->next_remaining_bytes = total - len;
+
+               spi_writel(as, RNPR, rx_dma);
+               spi_writel(as, TNPR, tx_dma);
+
+               if (msg->spi->bits_per_word > 8)
+                       len >>= 1;
+               spi_writel(as, RNCR, len);
+               spi_writel(as, TNCR, len);
+
+               dev_dbg(&msg->spi->dev,
+                       "  next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+                       xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+                       xfer->rx_buf, xfer->rx_dma);
+       } else {
+               spi_writel(as, RNCR, 0);
+               spi_writel(as, TNCR, 0);
+       }
+
+       /* REVISIT: We're waiting for ENDRX before we start the next
         * transfer because we need to handle some difficult timing
         * issues otherwise. If we wait for ENDTX in one transfer and
         * then starts waiting for ENDRX in the next, it's difficult
@@ -186,17 +255,7 @@ static void atmel_spi_next_xfer(struct spi_master *master,
         *
         * It should be doable, though. Just not now...
         */
-       spi_writel(as, TNCR, 0);
-       spi_writel(as, RNCR, 0);
        spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
-
-       dev_dbg(&msg->spi->dev,
-               "  start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
-               xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
-               xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
-
-       spi_writel(as, RCR, len);
-       spi_writel(as, TCR, len);
        spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
 }
 
@@ -294,6 +353,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
        spin_lock(&as->lock);
 
        as->current_transfer = NULL;
+       as->next_transfer = NULL;
 
        /* continue if needed */
        if (list_empty(&as->queue) || as->stopping)
@@ -377,7 +437,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
 
                spi_writel(as, IDR, pending);
 
-               if (as->remaining_bytes == 0) {
+               if (as->current_remaining_bytes == 0) {
                        msg->actual_length += xfer->len;
 
                        if (!msg->is_dma_mapped)
@@ -387,7 +447,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
                        if (xfer->delay_usecs)
                                udelay(xfer->delay_usecs);
 
-                       if (msg->transfers.prev == &xfer->transfer_list) {
+                       if (atmel_spi_xfer_is_last(msg, xfer)) {
                                /* report completed message */
                                atmel_spi_msg_done(master, as, msg, 0,
                                                xfer->cs_change);
@@ -490,9 +550,14 @@ static int atmel_spi_setup(struct spi_device *spi)
        if (!(spi->mode & SPI_CPHA))
                csr |= SPI_BIT(NCPHA);
 
-       /* TODO: DLYBS and DLYBCT */
-       csr |= SPI_BF(DLYBS, 10);
-       csr |= SPI_BF(DLYBCT, 10);
+       /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
+        *
+        * DLYBCT would add delays between words, slowing down transfers.
+        * It could potentially be useful to cope with DMA bottlenecks, but
+        * in those cases it's probably best to just use a lower bitrate.
+        */
+       csr |= SPI_BF(DLYBS, 0);
+       csr |= SPI_BF(DLYBCT, 0);
 
        /* chipselect must have been muxed as GPIO (e.g. in board setup) */
        npcs_pin = (unsigned int)spi->controller_data;
index ea61724..a6ba11a 100644 (file)
@@ -915,6 +915,28 @@ static u8 __initdata spi2_txdma_id[] = {
        OMAP24XX_DMA_SPI2_TX1,
 };
 
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+static u8 __initdata spi3_rxdma_id[] = {
+       OMAP24XX_DMA_SPI3_RX0,
+       OMAP24XX_DMA_SPI3_RX1,
+};
+
+static u8 __initdata spi3_txdma_id[] = {
+       OMAP24XX_DMA_SPI3_TX0,
+       OMAP24XX_DMA_SPI3_TX1,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static u8 __initdata spi4_rxdma_id[] = {
+       OMAP34XX_DMA_SPI4_RX0,
+};
+
+static u8 __initdata spi4_txdma_id[] = {
+       OMAP34XX_DMA_SPI4_TX0,
+};
+#endif
+
 static int __init omap2_mcspi_probe(struct platform_device *pdev)
 {
        struct spi_master       *master;
@@ -935,7 +957,20 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
                txdma_id = spi2_txdma_id;
                num_chipselect = 2;
                break;
-       /* REVISIT omap2430 has a third McSPI ... */
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+       case 3:
+               rxdma_id = spi3_rxdma_id;
+               txdma_id = spi3_txdma_id;
+               num_chipselect = 2;
+               break;
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+       case 4:
+               rxdma_id = spi4_rxdma_id;
+               txdma_id = spi4_txdma_id;
+               num_chipselect = 1;
+               break;
+#endif
        default:
                return -EINVAL;
        }
index eb817b8..365e0e3 100644 (file)
@@ -1526,17 +1526,6 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
-       pm_message_t *state = pm_message;
-
-       if (dev->power.power_state.event != state->event) {
-               dev_warn(dev, "pm state does not match request\n");
-               return -1;
-       }
-
-       return 0;
-}
 
 static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
 {
@@ -1544,12 +1533,6 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
        struct ssp_device *ssp = drv_data->ssp;
        int status = 0;
 
-       /* Check all childern for current power state */
-       if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) {
-               dev_warn(&pdev->dev, "suspend aborted\n");
-               return -1;
-       }
-
        status = stop_queue(drv_data);
        if (status != 0)
                return status;
index 682a6a4..1ad12af 100644 (file)
@@ -18,7 +18,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/autoconf.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -77,39 +76,33 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 #ifdef CONFIG_PM
 
-/*
- * NOTE:  the suspend() method for an spi_master controller driver
- * should verify that all its child devices are marked as suspended;
- * suspend requests delivered through sysfs power/state files don't
- * enforce such constraints.
- */
 static int spi_suspend(struct device *dev, pm_message_t message)
 {
-       int                     value;
+       int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
 
-       if (!drv || !drv->suspend)
-               return 0;
-
        /* suspend will stop irqs and dma; no more i/o */
-       value = drv->suspend(to_spi_device(dev), message);
-       if (value == 0)
-               dev->power.power_state = message;
+       if (drv) {
+               if (drv->suspend)
+                       value = drv->suspend(to_spi_device(dev), message);
+               else
+                       dev_dbg(dev, "... can't suspend\n");
+       }
        return value;
 }
 
 static int spi_resume(struct device *dev)
 {
-       int                     value;
+       int                     value = 0;
        struct spi_driver       *drv = to_spi_driver(dev->driver);
 
-       if (!drv || !drv->resume)
-               return 0;
-
        /* resume may restart the i/o queue */
-       value = drv->resume(to_spi_device(dev));
-       if (value == 0)
-               dev->power.power_state = PMSG_ON;
+       if (drv) {
+               if (drv->resume)
+                       value = drv->resume(to_spi_device(dev));
+               else
+                       dev_dbg(dev, "... can't resume\n");
+       }
        return value;
 }
 
index 7ef39a6..d853fce 100644 (file)
@@ -1,37 +1,11 @@
 /*
- * File:       drivers/spi/bfin5xx_spi.c
- * Maintainer:
- *             Bryan Wu <bryan.wu@analog.com>
- * Original Author:
- *             Luke Yang (Analog Devices Inc.)
- *
- * Created:    March. 10th 2006
- * Description:        SPI controller driver for Blackfin BF5xx
- * Bugs:       Enter bugs at http://blackfin.uclinux.org/
- *
- * Modified:
- *     March 10, 2006  bfin5xx_spi.c Created. (Luke Yang)
- *      August 7, 2006  added full duplex mode (Axel Weiss & Luke Yang)
- *      July  17, 2007  add support for BF54x SPI0 controller (Bryan Wu)
- *      July  30, 2007  add platfrom_resource interface to support multi-port
- *                      SPI controller (Bryan Wu)
+ * Blackfin On-Chip SPI Driver
  *
  * Copyright 2004-2007 Analog Devices Inc.
  *
- * This program is free software ;  you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ;  either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ;  without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Enter bugs at http://blackfin.uclinux.org/
  *
- * You should have received a copy of the GNU General Public License
- * along with this program ;  see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/init.h>
@@ -223,10 +197,9 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
 #define MAX_SPI_SSEL   7
 
 /* stop controller and re-config current chip*/
-static int restore_state(struct driver_data *drv_data)
+static void restore_state(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
-       int ret = 0;
 
        /* Clear status and disable clock */
        write_STAT(drv_data, BIT_STAT_CLR);
@@ -239,13 +212,6 @@ static int restore_state(struct driver_data *drv_data)
 
        bfin_spi_enable(drv_data);
        cs_active(drv_data, chip);
-
-       if (ret)
-               dev_dbg(&drv_data->pdev->dev,
-                       ": request chip select number %d failed\n",
-                       chip->chip_select_num);
-
-       return ret;
 }
 
 /* used to kick off transfer in rx mode */
@@ -286,32 +252,30 @@ static void u8_writer(struct driver_data *drv_data)
        dev_dbg(&drv_data->pdev->dev,
                "cr8-s is 0x%x\n", read_STAT(drv_data));
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
                while (read_STAT(drv_data) & BIT_STAT_TXS)
                        cpu_relax();
                ++drv_data->tx;
        }
+
+       /* poll for SPI completion before return */
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+               cpu_relax();
 }
 
 static void u8_cs_chg_writer(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
                while (read_STAT(drv_data) & BIT_STAT_TXS)
                        cpu_relax();
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+                       cpu_relax();
 
                cs_deactive(drv_data, chip);
 
@@ -350,43 +314,28 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
-       /* clear TDBR buffer before read(else it will be shifted out) */
-       write_TDBR(drv_data, 0xFFFF);
+       while (drv_data->rx < drv_data->rx_end) {
+               cs_active(drv_data, chip);
+               read_RDBR(drv_data);    /* kick off */
 
-       cs_active(drv_data, chip);
-       dummy_read(drv_data);
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+                       cpu_relax();
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+                       cpu_relax();
 
-       while (drv_data->rx < drv_data->rx_end - 1) {
+               *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
                cs_deactive(drv_data, chip);
 
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               cs_active(drv_data, chip);
-               *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
                ++drv_data->rx;
        }
-       cs_deactive(drv_data, chip);
-
-       while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-               cpu_relax();
-       *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
-       ++drv_data->rx;
 }
 
 static void u8_duplex(struct driver_data *drv_data)
 {
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        /* in duplex mode, clk is triggered by writing of TDBR */
        while (drv_data->rx < drv_data->rx_end) {
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -400,15 +349,12 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->rx < drv_data->rx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -426,32 +372,30 @@ static void u16_writer(struct driver_data *drv_data)
        dev_dbg(&drv_data->pdev->dev,
                "cr16 is 0x%x\n", read_STAT(drv_data));
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
                while ((read_STAT(drv_data) & BIT_STAT_TXS))
                        cpu_relax();
                drv_data->tx += 2;
        }
+
+       /* poll for SPI completion before return */
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+               cpu_relax();
 }
 
 static void u16_cs_chg_writer(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
                while ((read_STAT(drv_data) & BIT_STAT_TXS))
                        cpu_relax();
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+                       cpu_relax();
 
                cs_deactive(drv_data, chip);
 
@@ -519,14 +463,10 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
 
 static void u16_duplex(struct driver_data *drv_data)
 {
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        /* in duplex mode, clk is triggered by writing of TDBR */
        while (drv_data->tx < drv_data->tx_end) {
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -540,15 +480,11 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
        while (drv_data->tx < drv_data->tx_end) {
                cs_active(drv_data, chip);
 
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                        cpu_relax();
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
@@ -616,7 +552,7 @@ static void giveback(struct driver_data *drv_data)
 
 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
 {
-       struct driver_data *drv_data = (struct driver_data *)dev_id;
+       struct driver_data *drv_data = dev_id;
        struct chip_data *chip = drv_data->cur_chip;
        struct spi_message *msg = drv_data->cur_msg;
 
@@ -978,10 +914,7 @@ static void pump_messages(struct work_struct *work)
 
        /* Setup the SSP using the per chip configuration */
        drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
-       if (restore_state(drv_data)) {
-               spin_unlock_irqrestore(&drv_data->lock, flags);
-               return;
-       };
+       restore_state(drv_data);
 
        list_del_init(&drv_data->cur_msg->queue);
 
@@ -1187,7 +1120,7 @@ static int setup(struct spi_device *spi)
        if ((chip->chip_select_num > 0)
                && (chip->chip_select_num <= spi->master->num_chipselect))
                peripheral_request(ssel[spi->master->bus_num]
-                       [chip->chip_select_num-1], DRV_NAME);
+                       [chip->chip_select_num-1], spi->modalias);
 
        cs_deactive(drv_data, chip);
 
index 639963e..1b06471 100644 (file)
@@ -1686,17 +1686,6 @@ static void spi_imx_shutdown(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int suspend_devices(struct device *dev, void *pm_message)
-{
-       pm_message_t *state = pm_message;
-
-       if (dev->power.power_state.event != state->event) {
-               dev_warn(dev, "pm state does not match request\n");
-               return -1;
-       }
-
-       return 0;
-}
 
 static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
 {
index 89d6685..6e834b8 100644 (file)
@@ -237,10 +237,8 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
 {
        struct s3c24xx_spi *hw;
        struct spi_master *master;
-       struct spi_board_info *bi;
        struct resource *res;
        int err = 0;
-       int i;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
        if (master == NULL) {
@@ -348,16 +346,6 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
                goto err_register;
        }
 
-       /* register all the devices associated */
-
-       bi = &hw->pdata->board_info[0];
-       for (i = 0; i < hw->pdata->board_size; i++, bi++) {
-               dev_info(hw->dev, "registering %s\n", bi->modalias);
-
-               bi->controller_data = hw;
-               spi_new_device(master, bi);
-       }
-
        return 0;
 
  err_register:
index 109d82c..82ae7d7 100644 (file)
@@ -100,7 +100,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
        struct spi_master       *master;
        struct s3c2410_spigpio  *sp;
        int ret;
-       int i;
 
        master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
        if (master == NULL) {
@@ -143,17 +142,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
        if (ret)
                goto err_no_bitbang;
 
-       /* register the chips to go with the board */
-
-       for (i = 0; i < sp->info->board_size; i++) {
-               dev_info(&dev->dev, "registering %p: %s\n",
-                        &sp->info->board_info[i],
-                        sp->info->board_info[i].modalias);
-
-               sp->info->board_info[i].controller_data = sp;
-               spi_new_device(master, sp->info->board_info + i);
-       }
-
        return 0;
 
  err_no_bitbang:
diff --git a/drivers/spi/spi_sh_sci.c b/drivers/spi/spi_sh_sci.c
new file mode 100644 (file)
index 0000000..3dbe71b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * SH SCI SPI interface
+ *
+ * Copyright (c) 2008 Magnus Damm
+ *
+ * Based on S3C24XX GPIO based SPI driver, which is:
+ *   Copyright (c) 2006 Ben Dooks
+ *   Copyright (c) 2006 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/spi.h>
+#include <asm/io.h>
+
+struct sh_sci_spi {
+       struct spi_bitbang bitbang;
+
+       void __iomem *membase;
+       unsigned char val;
+       struct sh_spi_info *info;
+       struct platform_device *dev;
+};
+
+#define SCSPTR(sp)     (sp->membase + 0x1c)
+#define PIN_SCK                (1 << 2)
+#define PIN_TXD                (1 << 0)
+#define PIN_RXD                PIN_TXD
+#define PIN_INIT       ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
+
+static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
+{
+       /*
+        * We are the only user of SCSPTR so no locking is required.
+        * Reading bit 2 and 0 in SCSPTR gives pin state as input.
+        * Writing the same bits sets the output value.
+        * This makes regular read-modify-write difficult so we
+        * use sp->val to keep track of the latest register value.
+        */
+
+       if (on)
+               sp->val |= bits;
+       else
+               sp->val &= ~bits;
+
+       iowrite8(sp->val, SCSPTR(sp));
+}
+
+static inline void setsck(struct spi_device *dev, int on)
+{
+       setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
+}
+
+static inline void setmosi(struct spi_device *dev, int on)
+{
+       setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+       struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+       return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
+}
+
+#define spidelay(x) ndelay(x)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
+                                     unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
+{
+       struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+
+       if (sp->info && sp->info->chip_select)
+               (sp->info->chip_select)(sp->info, dev->chip_select, value);
+}
+
+static int sh_sci_spi_probe(struct platform_device *dev)
+{
+       struct resource *r;
+       struct spi_master *master;
+       struct sh_sci_spi *sp;
+       int ret;
+
+       master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
+       if (master == NULL) {
+               dev_err(&dev->dev, "failed to allocate spi master\n");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       sp = spi_master_get_devdata(master);
+
+       platform_set_drvdata(dev, sp);
+       sp->info = dev->dev.platform_data;
+
+       /* setup spi bitbang adaptor */
+       sp->bitbang.master = spi_master_get(master);
+       sp->bitbang.master->bus_num = sp->info->bus_num;
+       sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
+       sp->bitbang.chipselect = sh_sci_spi_chipselect;
+
+       sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
+       sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
+       sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
+       sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
+
+       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               ret = -ENOENT;
+               goto err1;
+       }
+       sp->membase = ioremap(r->start, r->end - r->start + 1);
+       if (!sp->membase) {
+               ret = -ENXIO;
+               goto err1;
+       }
+       sp->val = ioread8(SCSPTR(sp));
+       setbits(sp, PIN_INIT, 1);
+
+       ret = spi_bitbang_start(&sp->bitbang);
+       if (!ret)
+               return 0;
+
+       setbits(sp, PIN_INIT, 0);
+       iounmap(sp->membase);
+ err1:
+       spi_master_put(sp->bitbang.master);
+ err0:
+       return ret;
+}
+
+static int sh_sci_spi_remove(struct platform_device *dev)
+{
+       struct sh_sci_spi *sp = platform_get_drvdata(dev);
+
+       iounmap(sp->membase);
+       setbits(sp, PIN_INIT, 0);
+       spi_bitbang_stop(&sp->bitbang);
+       spi_master_put(sp->bitbang.master);
+       return 0;
+}
+
+static struct platform_driver sh_sci_spi_drv = {
+       .probe          = sh_sci_spi_probe,
+       .remove         = sh_sci_spi_remove,
+       .driver         = {
+               .name   = "spi_sh_sci",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sh_sci_spi_init(void)
+{
+       return platform_driver_register(&sh_sci_spi_drv);
+}
+module_init(sh_sci_spi_init);
+
+static void __exit sh_sci_spi_exit(void)
+{
+       platform_driver_unregister(&sh_sci_spi_drv);
+}
+module_exit(sh_sci_spi_exit);
+
+MODULE_DESCRIPTION("SH SCI SPI Driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
index cc246fa..2a77e9d 100644 (file)
@@ -417,30 +417,28 @@ static void uio_vma_close(struct vm_area_struct *vma)
        idev->vma_count--;
 }
 
-static struct page *uio_vma_nopage(struct vm_area_struct *vma,
-                                  unsigned long address, int *type)
+static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct uio_device *idev = vma->vm_private_data;
-       struct page* page = NOPAGE_SIGBUS;
+       struct page *page;
 
        int mi = uio_find_mem_index(vma);
        if (mi < 0)
-               return page;
+               return VM_FAULT_SIGBUS;
 
        if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
                page = virt_to_page(idev->info->mem[mi].addr);
        else
                page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
        get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = page;
+       return 0;
 }
 
 static struct vm_operations_struct uio_vm_ops = {
        .open = uio_vma_open,
        .close = uio_vma_close,
-       .nopage = uio_vma_nopage,
+       .fault = uio_vma_fault,
 };
 
 static int uio_mmap_physical(struct vm_area_struct *vma)
index f8e7111..fc65c02 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/backlight.h>
 
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
@@ -69,6 +70,107 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
 }
 #endif
 
+static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+               | ATMEL_LCDC_POL_POSITIVE
+               | ATMEL_LCDC_ENA_PWMENABLE;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+/* some bl->props field just changed */
+static int atmel_bl_update_status(struct backlight_device *bl)
+{
+       struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+       int                     power = sinfo->bl_power;
+       int                     brightness = bl->props.brightness;
+
+       /* REVISIT there may be a meaningful difference between
+        * fb_blank and power ... there seem to be some cases
+        * this doesn't handle correctly.
+        */
+       if (bl->props.fb_blank != sinfo->bl_power)
+               power = bl->props.fb_blank;
+       else if (bl->props.power != sinfo->bl_power)
+               power = bl->props.power;
+
+       if (brightness < 0 && power == FB_BLANK_UNBLANK)
+               brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+       else if (power != FB_BLANK_UNBLANK)
+               brightness = 0;
+
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+                       brightness ? contrast_ctr : 0);
+
+       bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+       return 0;
+}
+
+static int atmel_bl_get_brightness(struct backlight_device *bl)
+{
+       struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+
+       return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+}
+
+static struct backlight_ops atmel_lcdc_bl_ops = {
+       .update_status = atmel_bl_update_status,
+       .get_brightness = atmel_bl_get_brightness,
+};
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+       struct backlight_device *bl;
+
+       sinfo->bl_power = FB_BLANK_UNBLANK;
+
+       if (sinfo->backlight)
+               return;
+
+       bl = backlight_device_register("backlight", &sinfo->pdev->dev,
+                       sinfo, &atmel_lcdc_bl_ops);
+       if (IS_ERR(sinfo->backlight)) {
+               dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+                               PTR_ERR(bl));
+               return;
+       }
+       sinfo->backlight = bl;
+
+       bl->props.power = FB_BLANK_UNBLANK;
+       bl->props.fb_blank = FB_BLANK_UNBLANK;
+       bl->props.max_brightness = 0xff;
+       bl->props.brightness = atmel_bl_get_brightness(bl);
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+       if (sinfo->backlight)
+               backlight_device_unregister(sinfo->backlight);
+}
+
+#else
+
+static void init_backlight(struct atmel_lcdfb_info *sinfo)
+{
+       dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
+}
+
+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+{
+}
+
+#endif
+
+static void init_contrast(struct atmel_lcdfb_info *sinfo)
+{
+       /* have some default contrast/backlight settings */
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+
+       if (sinfo->lcdcon_is_backlight)
+               init_backlight(sinfo);
+}
+
 
 static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
        .type           = FB_TYPE_PACKED_PIXELS,
@@ -203,6 +305,26 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        var->transp.offset = var->transp.length = 0;
        var->xoffset = var->yoffset = 0;
 
+       /* Saturate vertical and horizontal timings at maximum values */
+       var->vsync_len = min_t(u32, var->vsync_len,
+                       (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+       var->upper_margin = min_t(u32, var->upper_margin,
+                       ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+       var->lower_margin = min_t(u32, var->lower_margin,
+                       ATMEL_LCDC_VFP);
+       var->right_margin = min_t(u32, var->right_margin,
+                       (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+       var->hsync_len = min_t(u32, var->hsync_len,
+                       (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+       var->left_margin = min_t(u32, var->left_margin,
+                       ATMEL_LCDC_HBP + 1);
+
+       /* Some parameters can't be zero */
+       var->vsync_len = max_t(u32, var->vsync_len, 1);
+       var->right_margin = max_t(u32, var->right_margin, 1);
+       var->hsync_len = max_t(u32, var->hsync_len, 1);
+       var->left_margin = max_t(u32, var->left_margin, 1);
+
        switch (var->bits_per_pixel) {
        case 1:
        case 2:
@@ -370,10 +492,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
        /* Disable all interrupts */
        lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
 
-       /* Set contrast */
-       value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
-       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
-       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
        /* ...wait for DMA engine to become idle... */
        while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
                msleep(10);
@@ -577,6 +695,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                sinfo->default_monspecs = pdata_sinfo->default_monspecs;
                sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
                sinfo->guard_time = pdata_sinfo->guard_time;
+               sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
        } else {
                dev_err(dev, "cannot get default configuration\n");
                goto free_info;
@@ -670,6 +789,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                goto release_mem;
        }
 
+       /* Initialize PWM for contrast or backlight ("off") */
+       init_contrast(sinfo);
+
        /* interrupt */
        ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
        if (ret) {
@@ -721,6 +843,7 @@ free_cmap:
 unregister_irqs:
        free_irq(sinfo->irq_base, info);
 unmap_mmio:
+       exit_backlight(sinfo);
        iounmap(sinfo->mmio);
 release_mem:
        release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
@@ -755,6 +878,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
        if (!sinfo)
                return 0;
 
+       exit_backlight(sinfo);
        if (sinfo->atmel_lcdfb_power_control)
                sinfo->atmel_lcdfb_power_control(0);
        unregister_framebuffer(info);
@@ -781,6 +905,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
 
 static struct platform_driver atmel_lcdfb_driver = {
        .remove         = __exit_p(atmel_lcdfb_remove),
+
+// FIXME need suspend, resume
+
        .driver         = {
                .name   = "atmel_lcdfb",
                .owner  = THIS_MODULE,
index 9609a6c..924e255 100644 (file)
@@ -50,6 +50,19 @@ config BACKLIGHT_CLASS_DEVICE
          To have support for your specific LCD panel you will have to
          select the proper drivers which depend on this option.
 
+config BACKLIGHT_ATMEL_LCDC
+       bool "Atmel LCDC Contrast-as-Backlight control"
+       depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
+       default y if MACH_SAM9261EK || MACH_SAM9263EK
+       help
+         This provides a backlight control internal to the Atmel LCDC
+         driver.  If the LCD "contrast control" on your board is wired
+         so it controls the backlight brightness, select this option to
+         export this as a PWM-based backlight control.
+
+         If in doubt, it's safe to enable this option; it doesn't kick
+         in unless the board's description says it's wired that way.
+
 config BACKLIGHT_CORGI
        tristate "Generic (aka Sharp Corgi) Backlight Driver"
        depends on BACKLIGHT_CLASS_DEVICE
index c8e7427..0ce791e 100644 (file)
@@ -498,8 +498,7 @@ static struct lcd_device *lcd_dev;
 
 static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
 {
-
-       /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/
+       /*struct bfin_bf54xfb_info *info = dev_id;*/
 
        u16 status = bfin_read_EPPI0_STATUS();
 
index 308850d..69864b1 100644 (file)
@@ -63,7 +63,7 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
        struct fb_fillrect region;
 
-       region.color = attr_bgcol_ec(bgshift, vc);
+       region.color = attr_bgcol_ec(bgshift, vc, info);
        region.dx = sx * vc->vc_font.width;
        region.dy = sy * vc->vc_font.height;
        region.width = width * vc->vc_font.width;
@@ -213,7 +213,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
        unsigned int bs = info->var.yres - bh;
        struct fb_fillrect region;
 
-       region.color = attr_bgcol_ec(bgshift, vc);
+       region.color = attr_bgcol_ec(bgshift, vc, info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index 0f32f4a..0222824 100644 (file)
@@ -84,7 +84,7 @@
 #ifdef CONFIG_MAC
 #include <asm/macints.h>
 #endif
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
 #include <asm/machdep.h>
 #include <asm/setup.h>
 #endif
@@ -147,7 +147,7 @@ static char fontname[40];
 static int info_idx = -1;
 
 /* console rotation */
-static int rotate;
+static int initial_rotation;
 static int fbcon_has_sysfs;
 
 static const struct consw fb_con;
@@ -334,10 +334,7 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info,
        switch (depth) {
        case 1:
        {
-               int col = ~(0xfff << (max(info->var.green.length,
-                                         max(info->var.red.length,
-                                             info->var.blue.length)))) & 0xff;
-
+               int col = mono_col(info);
                /* 0 or 1 */
                int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0;
                int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col;
@@ -537,9 +534,9 @@ static int __init fb_console_setup(char *this_opt)
                if (!strncmp(options, "rotate:", 7)) {
                        options += 7;
                        if (*options)
-                               rotate = simple_strtoul(options, &options, 0);
-                       if (rotate > 3)
-                               rotate = 0;
+                               initial_rotation = simple_strtoul(options, &options, 0);
+                       if (initial_rotation > 3)
+                               initial_rotation = 0;
                }
        }
        return 1;
@@ -989,7 +986,7 @@ static const char *fbcon_startup(void)
        ops->graphics = 1;
        ops->cur_rotate = -1;
        info->fbcon_par = ops;
-       p->con_rotate = rotate;
+       p->con_rotate = initial_rotation;
        set_blitting_type(vc, info);
 
        if (info->fix.type != FB_TYPE_TEXT) {
@@ -1176,7 +1173,7 @@ static void fbcon_init(struct vc_data *vc, int init)
                con_copy_unimap(vc, svc);
 
        ops = info->fbcon_par;
-       p->con_rotate = rotate;
+       p->con_rotate = initial_rotation;
        set_blitting_type(vc, info);
 
        cols = vc->vc_cols;
@@ -2795,7 +2792,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
 {
        struct fb_info *info = registered_fb[con2fb_map[fg_console]];
        struct fbcon_ops *ops = info->fbcon_par;
-       struct display *p = &fb_display[fg_console];
+       struct display *disp = &fb_display[fg_console];
        int offset, limit, scrollback_old;
 
        if (softback_top) {
@@ -2833,7 +2830,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
                        logo_shown = FBCON_LOGO_CANSHOW;
                }
                fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
-               fbcon_redraw_softback(vc, p, lines);
+               fbcon_redraw_softback(vc, disp, lines);
                fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
                return 0;
        }
@@ -2855,9 +2852,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
 
        fbcon_cursor(vc, CM_ERASE);
 
-       offset = p->yscroll - scrollback_current;
-       limit = p->vrows;
-       switch (p->scrollmode) {
+       offset = disp->yscroll - scrollback_current;
+       limit = disp->vrows;
+       switch (disp->scrollmode) {
        case SCROLL_WRAP_MOVE:
                info->var.vmode |= FB_VMODE_YWRAP;
                break;
index 8e6ef4b..3706307 100644 (file)
@@ -93,10 +93,6 @@ struct fbcon_ops {
        (((s) >> (fgshift)) & 0x0f)
 #define attr_bgcol(bgshift,s)    \
        (((s) >> (bgshift)) & 0x0f)
-#define        attr_bgcol_ec(bgshift,vc) \
-       ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0)
-#define attr_fgcol_ec(fgshift,vc) \
-       ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0)
 
 /* Monochrome */
 #define attr_bold(s) \
@@ -108,6 +104,49 @@ struct fbcon_ops {
 #define attr_blink(s) \
        ((s) & 0x8000)
        
+#define mono_col(info)                                                 \
+       (~(0xfff << (max((info)->var.green.length,                      \
+                        max((info)->var.red.length,                    \
+                            (info)->var.blue.length)))) & 0xff)
+
+static inline int attr_col_ec(int shift, struct vc_data *vc,
+                             struct fb_info *info, int is_fg)
+{
+       int is_mono01;
+       int col;
+       int fg;
+       int bg;
+
+       if (!vc)
+               return 0;
+
+       if (vc->vc_can_do_color)
+               return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char)
+                       : attr_bgcol(shift,vc->vc_video_erase_char);
+
+       if (!info)
+               return 0;
+
+       col = mono_col(info);
+       is_mono01 = info->fix.visual == FB_VISUAL_MONO01;
+
+       if (attr_reverse(vc->vc_video_erase_char)) {
+               fg = is_mono01 ? col : 0;
+               bg = is_mono01 ? 0 : col;
+       }
+       else {
+               fg = is_mono01 ? 0 : col;
+               bg = is_mono01 ? col : 0;
+       }
+
+       return is_fg ? fg : bg;
+}
+
+#define attr_bgcol_ec(bgshift,vc,info)         \
+       attr_col_ec(bgshift,vc,info,0);
+#define attr_fgcol_ec(fgshift,vc,info)         \
+       attr_col_ec(fgshift,vc,info,1);
+
 /* Font */
 #define REFCOUNT(fd)   (((int *)(fd))[-1])
 #define FNTSIZE(fd)    (((int *)(fd))[-2])
index 825e6d6..bdf913e 100644 (file)
@@ -84,7 +84,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
        u32 vyres = GETVYRES(ops->p->scrollmode, info);
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = sy * vc->vc_font.height;
        region.dy = vyres - ((sx + width) * vc->vc_font.width);
        region.height = width * vc->vc_font.width;
@@ -198,7 +198,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index c637e63..a6819b9 100644 (file)
@@ -70,7 +70,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
        u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = vxres - ((sy + height) * vc->vc_font.height);
        region.dy = sx *  vc->vc_font.width;
        region.height = width * vc->vc_font.width;
@@ -182,7 +182,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index 1473506..d9b5d6e 100644 (file)
@@ -71,7 +71,7 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
        u32 vyres = GETVYRES(ops->p->scrollmode, info);
        u32 vxres = GETVXRES(ops->p->scrollmode, info);
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dy = vyres - ((sy + height) * vc->vc_font.height);
        region.dx = vxres - ((sx + width) *  vc->vc_font.width);
        region.width = width * vc->vc_font.width;
@@ -228,7 +228,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
 
-       region.color = attr_bgcol_ec(bgshift,vc);
+       region.color = attr_bgcol_ec(bgshift,vc,info);
        region.rop = ROP_COPY;
 
        if (rw && !bottom_only) {
index 96979c3..d0c03fd 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
 #include <asm/setup.h>
 #endif
 #include <linux/font.h>
@@ -120,7 +120,7 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
     for(i=0; i<num_fonts; i++) {
        f = fonts[i];
        c = f->pref;
-#if defined(__mc68000__) || defined(CONFIG_APUS)
+#if defined(__mc68000__)
 #ifdef CONFIG_FONT_PEARL_8x8
        if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
            c = 100;
index d981fe4..0056a41 100644 (file)
@@ -40,8 +40,8 @@ static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
 
        rect.index = vc->vc_video_erase_char &
                ((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
-       rect.fg = attr_fgcol_ec(fgshift, vc);
-       rect.bg = attr_bgcol_ec(bgshift, vc);
+       rect.fg = attr_fgcol_ec(fgshift, vc, info);
+       rect.bg = attr_bgcol_ec(bgshift, vc, info);
        rect.sx = sx;
        rect.sy = sy;
        rect.width = width;
index f65bcd3..6df29a6 100644 (file)
@@ -1153,8 +1153,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
 
        /* if 512 char mode is already enabled don't re-enable it. */
        if ((set) && (ch512 != vga_512_chars)) {
-               int i;  
-               
                /* attribute controller */
                for (i = 0; i < MAX_NR_CONSOLES; i++) {
                        struct vc_data *c = vc_cons[i].d;
index a0c5d9d..0f8cfb9 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/pagemap.h>
 
 /* this is to find and return the vmalloc-ed fb pages */
-static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
-                                       unsigned long vaddr, int *type)
+static int fb_deferred_io_fault(struct vm_area_struct *vma,
+                               struct vm_fault *vmf)
 {
        unsigned long offset;
        struct page *page;
@@ -34,18 +34,17 @@ static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
        /* info->screen_base is in System RAM */
        void *screen_base = (void __force *) info->screen_base;
 
-       offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+       offset = vmf->pgoff << PAGE_SHIFT;
        if (offset >= info->fix.smem_len)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_SIGBUS;
 
        page = vmalloc_to_page(screen_base + offset);
        if (!page)
-               return NOPAGE_OOM;
+               return VM_FAULT_SIGBUS;
 
        get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = page;
+       return 0;
 }
 
 int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
@@ -84,7 +83,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
 }
 
 static struct vm_operations_struct fb_deferred_io_vm_ops = {
-       .nopage         = fb_deferred_io_nopage,
+       .fault          = fb_deferred_io_fault,
        .page_mkwrite   = fb_deferred_io_mkwrite,
 };
 
index cdafbe1..a2a0618 100644 (file)
@@ -91,6 +91,7 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
                val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
        if (bswapmask & 3)
                val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
+       return val;
 }
 
 static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
index 4ba9c08..052e180 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
  *
  * Credits:
- * 
+ *
  * The EDID Parser is a conglomeration from the following sources:
  *
  *   1. SciTech SNAP Graphics Architecture
  *
  *   2. XFree86 4.3.0, interpret_edid.c
  *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
- * 
- *   3. John Fremlin <vii@users.sourceforge.net> and 
+ *
+ *   3. John Fremlin <vii@users.sourceforge.net> and
  *      Ani Joshi <ajoshi@unixbox.com>
- *  
+ *
  * Generalized Timing Formula is derived from:
  *
- *      GTF Spreadsheet by Andy Morrish (1/5/97) 
+ *      GTF Spreadsheet by Andy Morrish (1/5/97)
  *      available at http://www.vesa.org
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -36,7 +36,7 @@
 #endif
 #include "edid.h"
 
-/* 
+/*
  * EDID parser
  */
 
@@ -160,8 +160,8 @@ static int check_edid(unsigned char *edid)
        for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
                if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
                        brokendb[i].model == model) {
-                       fix = brokendb[i].fix;
-                       break;
+                       fix = brokendb[i].fix;
+                       break;
                }
        }
 
@@ -323,7 +323,7 @@ static void get_dpms_capabilities(unsigned char flags,
               (flags & DPMS_SUSPEND)    ? "yes" : "no",
               (flags & DPMS_STANDBY)    ? "yes" : "no");
 }
-       
+
 static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
 {
        int tmp;
@@ -365,7 +365,7 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
        tmp += 512;
        specs->chroma.bluey = tmp/1024;
        DPRINTK("BlueY:    0.%03d\n", specs->chroma.bluey);
-       
+
        tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
        tmp *= 1000;
        tmp += 512;
@@ -383,7 +383,7 @@ static void calc_mode_timings(int xres, int yres, int refresh,
                              struct fb_videomode *mode)
 {
        struct fb_var_screeninfo *var;
-       
+
        var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
 
        if (var) {
@@ -451,11 +451,11 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
 
        c = block[1];
        if (c&0x80) {
-               mode[num++] = vesa_modes[9];
+               mode[num++] = vesa_modes[9];
                DPRINTK("      800x600@72Hz\n");
        }
        if (c&0x40) {
-               mode[num++] = vesa_modes[10];
+               mode[num++] = vesa_modes[10];
                DPRINTK("      800x600@75Hz\n");
        }
        if (c&0x20) {
@@ -495,7 +495,7 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
 static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
 {
        int xres, yres = 0, refresh, ratio, i;
-       
+
        xres = (block[0] + 31) * 8;
        if (xres <= 256)
                return 0;
@@ -519,7 +519,7 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode)
 
        DPRINTK("      %dx%d@%dHz\n", xres, yres, refresh);
        for (i = 0; i < VESA_MODEDB_SIZE; i++) {
-               if (vesa_modes[i].xres == xres && 
+               if (vesa_modes[i].xres == xres &&
                    vesa_modes[i].yres == yres &&
                    vesa_modes[i].refresh == refresh) {
                        *mode = vesa_modes[i];
@@ -536,13 +536,13 @@ static int get_dst_timing(unsigned char *block,
 {
        int j, num = 0;
 
-       for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE) 
+       for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
                num += get_std_timing(block, &mode[num]);
 
        return num;
 }
 
-static void get_detailed_timing(unsigned char *block, 
+static void get_detailed_timing(unsigned char *block,
                                struct fb_videomode *mode)
 {
        mode->xres = H_ACTIVE;
@@ -553,7 +553,7 @@ static void get_detailed_timing(unsigned char *block,
        mode->right_margin = H_SYNC_OFFSET;
        mode->left_margin = (H_ACTIVE + H_BLANKING) -
                (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
-       mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - 
+       mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
                V_SYNC_WIDTH;
        mode->lower_margin = V_SYNC_OFFSET;
        mode->hsync_len = H_SYNC_WIDTH;
@@ -597,7 +597,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
        if (mode == NULL)
                return NULL;
 
-       if (edid == NULL || !edid_checksum(edid) || 
+       if (edid == NULL || !edid_checksum(edid) ||
            !edid_check_header(edid)) {
                kfree(mode);
                return NULL;
@@ -632,7 +632,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
                if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
                        num += get_dst_timing(block + 5, &mode[num]);
        }
-       
+
        /* Yikes, EDID data is totally useless */
        if (!num) {
                kfree(mode);
@@ -686,7 +686,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
        /* estimate monitor limits based on modes supported */
        if (retval) {
                struct fb_videomode *modes, *mode;
-               int num_modes, i, hz, hscan, pixclock;
+               int num_modes, hz, hscan, pixclock;
                int vtotal, htotal;
 
                modes = fb_create_modedb(edid, &num_modes);
@@ -713,7 +713,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
                        hscan = (pixclock + htotal / 2) / htotal;
                        hscan = (hscan + 500) / 1000 * 1000;
                        hz = (hscan + vtotal / 2) / vtotal;
-                       
+
                        if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
                                specs->dclkmax = pixclock;
 
@@ -966,8 +966,8 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
        DPRINTK("========================================\n");
 }
 
-/* 
- * VESA Generalized Timing Formula (GTF) 
+/*
+ * VESA Generalized Timing Formula (GTF)
  */
 
 #define FLYBACK                     550
@@ -996,7 +996,7 @@ struct __fb_timings {
  * @hfreq: horizontal freq
  *
  * DESCRIPTION:
- * vblank = right_margin + vsync_len + left_margin 
+ * vblank = right_margin + vsync_len + left_margin
  *
  *    given: right_margin = 1 (V_FRONTPORCH)
  *           vsync_len    = 3
@@ -1010,12 +1010,12 @@ static u32 fb_get_vblank(u32 hfreq)
 {
        u32 vblank;
 
-       vblank = (hfreq * FLYBACK)/1000; 
+       vblank = (hfreq * FLYBACK)/1000;
        vblank = (vblank + 500)/1000;
        return (vblank + V_FRONTPORCH);
 }
 
-/** 
+/**
  * fb_get_hblank_by_freq - get horizontal blank time given hfreq
  * @hfreq: horizontal freq
  * @xres: horizontal resolution in pixels
@@ -1031,7 +1031,7 @@ static u32 fb_get_vblank(u32 hfreq)
  *
  * where: C = ((offset - scale factor) * blank_scale)
  *            -------------------------------------- + scale factor
- *                        256 
+ *                        256
  *        M = blank_scale * gradient
  *
  */
@@ -1039,7 +1039,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
 {
        u32 c_val, m_val, duty_cycle, hblank;
 
-       c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + 
+       c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
                 H_SCALEFACTOR) * 1000;
        m_val = (H_BLANKSCALE * H_GRADIENT)/256;
        m_val = (m_val * 1000000)/hfreq;
@@ -1048,7 +1048,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
        return (hblank);
 }
 
-/** 
+/**
  * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
  * @dclk: pixelclock in Hz
  * @xres: horizontal resolution in pixels
@@ -1061,7 +1061,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
  *
  * duty cycle = percent of htotal assigned to inactive display
  * duty cycle = C - (M * h_period)
- * 
+ *
  * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
  *                   -----------------------------------------------
  *                                    2 * M
@@ -1077,11 +1077,11 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
        h_period = 100 - C_VAL;
        h_period *= h_period;
        h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
-       h_period *=10000; 
+       h_period *= 10000;
 
        h_period = int_sqrt(h_period);
        h_period -= (100 - C_VAL) * 100;
-       h_period *= 1000; 
+       h_period *= 1000;
        h_period /= 2 * M_VAL;
 
        duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
@@ -1089,7 +1089,7 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
        hblank &= ~15;
        return (hblank);
 }
-       
+
 /**
  * fb_get_hfreq - estimate hsync
  * @vfreq: vertical refresh rate
@@ -1100,13 +1100,13 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
  *          (yres + front_port) * vfreq * 1000000
  * hfreq = -------------------------------------
  *          (1000000 - (vfreq * FLYBACK)
- * 
+ *
  */
 
 static u32 fb_get_hfreq(u32 vfreq, u32 yres)
 {
        u32 divisor, hfreq;
-       
+
        divisor = (1000000 - (vfreq * FLYBACK))/1000;
        hfreq = (yres + V_FRONTPORCH) * vfreq  * 1000;
        return (hfreq/divisor);
@@ -1117,7 +1117,7 @@ static void fb_timings_vfreq(struct __fb_timings *timings)
        timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
        timings->vblank = fb_get_vblank(timings->hfreq);
        timings->vtotal = timings->vactive + timings->vblank;
-       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 
+       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
                                                 timings->hactive);
        timings->htotal = timings->hactive + timings->hblank;
        timings->dclk = timings->htotal * timings->hfreq;
@@ -1128,7 +1128,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings)
        timings->vblank = fb_get_vblank(timings->hfreq);
        timings->vtotal = timings->vactive + timings->vblank;
        timings->vfreq = timings->hfreq/timings->vtotal;
-       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 
+       timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
                                                 timings->hactive);
        timings->htotal = timings->hactive + timings->hblank;
        timings->dclk = timings->htotal * timings->hfreq;
@@ -1136,7 +1136,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings)
 
 static void fb_timings_dclk(struct __fb_timings *timings)
 {
-       timings->hblank = fb_get_hblank_by_dclk(timings->dclk, 
+       timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
                                                timings->hactive);
        timings->htotal = timings->hactive + timings->hblank;
        timings->hfreq = timings->dclk/timings->htotal;
@@ -1156,29 +1156,29 @@ static void fb_timings_dclk(struct __fb_timings *timings)
  * @info: pointer to fb_info
  *
  * DESCRIPTION:
- * Calculates video mode based on monitor specs using VESA GTF. 
- * The GTF is best for VESA GTF compliant monitors but is 
+ * Calculates video mode based on monitor specs using VESA GTF.
+ * The GTF is best for VESA GTF compliant monitors but is
  * specifically formulated to work for older monitors as well.
  *
- * If @flag==0, the function will attempt to maximize the 
+ * If @flag==0, the function will attempt to maximize the
  * refresh rate.  Otherwise, it will calculate timings based on
- * the flag and accompanying value.  
+ * the flag and accompanying value.
  *
- * If FB_IGNOREMON bit is set in @flags, monitor specs will be 
+ * If FB_IGNOREMON bit is set in @flags, monitor specs will be
  * ignored and @var will be filled with the calculated timings.
  *
  * All calculations are based on the VESA GTF Spreadsheet
  * available at VESA's public ftp (http://www.vesa.org).
- * 
+ *
  * NOTES:
  * The timings generated by the GTF will be different from VESA
  * DMT.  It might be a good idea to keep a table of standard
  * VESA modes as well.  The GTF may also not work for some displays,
  * such as, and especially, analog TV.
- *   
+ *
  * REQUIRES:
  * A valid info->monspecs, otherwise 'safe numbers' will be used.
- */ 
+ */
 int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct __fb_timings *timings;
@@ -1191,7 +1191,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
        if (!timings)
                return -ENOMEM;
 
-       /* 
+       /*
         * If monspecs are invalid, use values that are enough
         * for 640x480@60
         */
@@ -1214,7 +1214,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
 
        timings->hactive = var->xres;
        timings->vactive = var->yres;
-       if (var->vmode & FB_VMODE_INTERLACED) { 
+       if (var->vmode & FB_VMODE_INTERLACED) {
                timings->vactive /= 2;
                interlace = 2;
        }
@@ -1250,9 +1250,9 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
                break;
        default:
                err = -EINVAL;
-               
-       } 
-       
+
+       }
+
        if (err || (!(flags & FB_IGNOREMON) &&
            (timings->vfreq < vfmin || timings->vfreq > vfmax ||
             timings->hfreq < hfmin || timings->hfreq > hfmax ||
@@ -1269,7 +1269,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
                var->upper_margin = (timings->vblank * interlace)/dscan -
                        (var->vsync_len + var->lower_margin);
        }
-       
+
        kfree(timings);
        return err;
 }
@@ -1291,7 +1291,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
        return -EINVAL;
 }
 #endif /* CONFIG_FB_MODE_HELPERS */
-       
+
 /*
  * fb_validate_mode - validates var against monitor capabilities
  * @var: pointer to fb_var_screeninfo
@@ -1309,7 +1309,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
        u32 hfreq, vfreq, htotal, vtotal, pixclock;
        u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
 
-       /* 
+       /*
         * If monspecs are invalid, use values that are enough
         * for 640x480@60
         */
@@ -1333,10 +1333,10 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
        if (!var->pixclock)
                return -EINVAL;
        pixclock = PICOS2KHZ(var->pixclock) * 1000;
-          
-       htotal = var->xres + var->right_margin + var->hsync_len + 
+
+       htotal = var->xres + var->right_margin + var->hsync_len +
                var->left_margin;
-       vtotal = var->yres + var->lower_margin + var->vsync_len + 
+       vtotal = var->yres + var->lower_margin + var->vsync_len +
                var->upper_margin;
 
        if (var->vmode & FB_VMODE_INTERLACED)
@@ -1349,7 +1349,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
 
        vfreq = hfreq/vtotal;
 
-       return (vfreq < vfmin || vfreq > vfmax || 
+       return (vfreq < vfmin || vfreq > vfmax ||
                hfreq < hfmin || hfreq > hfmax ||
                pixclock < dclkmin || pixclock > dclkmax) ?
                -EINVAL : 0;
index 583185f..eb6b881 100644 (file)
@@ -34,7 +34,7 @@ static int fbsize;
  * we try to make it something sane - 640x480-60 is sane
  */
 
-const struct fb_videomode geode_modedb[] __initdata = {
+static const struct fb_videomode geode_modedb[] __initdata = {
        /* 640x480-60 */
        { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
          FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
index b18486a..2eb4fb1 100644 (file)
@@ -207,7 +207,8 @@ static struct fb_ops hpfb_ops = {
 #define HPFB_FBOMSB    0x5d    /* Frame buffer offset          */
 #define HPFB_FBOLSB    0x5f
 
-static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
+static int __devinit hpfb_init_one(unsigned long phys_base,
+                                  unsigned long virt_base)
 {
        unsigned long fboff, fb_width, fb_height, fb_start;
 
index 1a7d778..1d13dd0 100644 (file)
@@ -1476,7 +1476,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        struct i810fb_par *par = info->par;
        u8 __iomem *mmio = par->mmio_start_virtual;
 
-       if (!par->dev_flags & LOCKUP)
+       if (!(par->dev_flags & LOCKUP))
                return -ENXIO;
 
        if (cursor->image.width > 64 || cursor->image.height > 64)
index b87ea21..3a81060 100644 (file)
@@ -400,6 +400,7 @@ int __init igafb_init(void)
         info = kzalloc(size, GFP_ATOMIC);
         if (!info) {
                 printk("igafb_init: can't alloc fb_info\n");
+                pci_dev_put(pdev);
                 return -ENOMEM;
         }
 
@@ -409,12 +410,14 @@ int __init igafb_init(void)
        if ((addr = pdev->resource[0].start) == 0) {
                 printk("igafb_init: no memory start\n");
                kfree(info);
+               pci_dev_put(pdev);
                return -ENXIO;
        }
 
        if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) {
                 printk("igafb_init: can't remap %lx[2M]\n", addr);
                kfree(info);
+               pci_dev_put(pdev);
                return -ENXIO;
        }
 
@@ -449,6 +452,7 @@ int __init igafb_init(void)
                 printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start);
                iounmap((void *)info->screen_base);
                kfree(info);
+               pci_dev_put(pdev);
                return -ENXIO;
        }
 
@@ -466,6 +470,7 @@ int __init igafb_init(void)
                iounmap((void *)par->io_base);
                iounmap(info->screen_base);
                kfree(info);
+               pci_dev_put(pdev);
                return -ENOMEM;
        }
 
index 5f6fb7d..fa1fff5 100644 (file)
@@ -1971,7 +1971,7 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
 static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
 {
        u16 tmp;
-       struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
+       struct intelfb_info *dinfo = dev_id;
 
        spin_lock(&dinfo->int_lock);
 
index 4b6a99b..5246b04 100644 (file)
@@ -2066,40 +2066,49 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
 
        switch (info->fix.accel) {
        case FB_ACCEL_NEOMAGIC_NM2070:
-               sprintf(info->fix.id, "MagicGraph 128");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128");
                break;
        case FB_ACCEL_NEOMAGIC_NM2090:
-               sprintf(info->fix.id, "MagicGraph 128V");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128V");
                break;
        case FB_ACCEL_NEOMAGIC_NM2093:
-               sprintf(info->fix.id, "MagicGraph 128ZV");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128ZV");
                break;
        case FB_ACCEL_NEOMAGIC_NM2097:
-               sprintf(info->fix.id, "MagicGraph 128ZV+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128ZV+");
                break;
        case FB_ACCEL_NEOMAGIC_NM2160:
-               sprintf(info->fix.id, "MagicGraph 128XD");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128XD");
                break;
        case FB_ACCEL_NEOMAGIC_NM2200:
-               sprintf(info->fix.id, "MagicGraph 256AV");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256AV");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2230:
-               sprintf(info->fix.id, "MagicGraph 256AV+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256AV+");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2360:
-               sprintf(info->fix.id, "MagicGraph 256ZX");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256ZX");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2380:
-               sprintf(info->fix.id, "MagicGraph 256XL+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256XL+");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
index 30e14eb..74517b1 100644 (file)
@@ -849,9 +849,27 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var,
        if (!mode_valid && info->monspecs.modedb_len)
                return -EINVAL;
 
+       /*
+        * If we're on a flat panel, check if the mode is outside of the
+        * panel dimensions. If so, cap it and try for the next best mode
+        * before bailing out.
+        */
        if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres ||
-                                             par->fpHeight < var->yres))
-               return -EINVAL;
+                                             par->fpHeight < var->yres)) {
+               const struct fb_videomode *mode;
+
+               var->xres = par->fpWidth;
+               var->yres = par->fpHeight;
+
+               mode = fb_find_best_mode(var, &info->modelist);
+               if (!mode) {
+                       printk(KERN_ERR PFX "mode out of range of flat "
+                              "panel dimensions\n");
+                       return -EINVAL;
+               }
+
+               fb_videomode_to_var(var, mode);
+       }
 
        if (var->yres_virtual < var->yres)
                var->yres_virtual = var->yres;
index 5591dfb..30181b5 100644 (file)
@@ -1159,6 +1159,11 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
        u32 fgx, bgx;
        const u32 *src = (const u32 *)image->data;
        u32 xres = (info->var.xres + 31) & ~31;
+       int raster_mode = 1; /* invert bits */
+
+#ifdef __LITTLE_ENDIAN
+       raster_mode |= 3 << 7; /* reverse byte order */
+#endif
 
        if (info->state != FBINFO_STATE_RUNNING)
                return;
@@ -1208,9 +1213,8 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
-               /* BitMapPackEachScanline & invert bits and byte order*/
-               /* force background */
-               pm2_WR(par, PM2R_RASTERIZER_MODE,  (1 << 9) | 1 | (3 << 7));
+               /* BitMapPackEachScanline */
+               pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9));
                pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
@@ -1224,8 +1228,7 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
                        PM2F_RENDER_RECTANGLE |
                        PM2F_RENDER_FASTFILL |
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
-               /* invert bits and byte order*/
-               pm2_WR(par, PM2R_RASTERIZER_MODE,  1 | (3 << 7));
+               pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode);
                pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
                pm2_WR(par, PM2R_RENDER,
                        PM2F_RENDER_RECTANGLE |
index 0706599..5dba8cd 100644 (file)
@@ -1227,7 +1227,7 @@ static struct fb_ops pm3fb_ops = {
 
 /* mmio register are already mapped when this function is called */
 /* the pm3fb_fix.smem_start is also set */
-static unsigned long pm3fb_size_memory(struct pm3_par *par)
+static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
 {
        unsigned long   memsize = 0;
        unsigned long   tempBypass, i, temp1, temp2;
index a864438..6515ec1 100644 (file)
@@ -150,7 +150,7 @@ static int aafbcon_set_font(struct display *disp, int width, int height)
 {
        struct aafb_info *info = (struct aafb_info *)disp->fb_info;
        struct aafb_cursor *c = &info->cursor;
-       u8 fgc = ~attr_bgcol_ec(disp, disp->conp);
+       u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info);
 
        if (width > 64 || height > 64 || width < 0 || height < 0)
                return -EINVAL;
index 044a423..dc3af1c 100644 (file)
@@ -57,8 +57,6 @@
 #define GPU_ALIGN_UP(x)                                _ALIGN_UP((x), 64)
 #define GPU_MAX_LINE_LENGTH                    (65536 - 64)
 
-#define PS3FB_FULL_MODE_BIT                    0x80
-
 #define GPU_INTR_STATUS_VSYNC_0                        0       /* vsync on head A */
 #define GPU_INTR_STATUS_VSYNC_1                        1       /* vsync on head B */
 #define GPU_INTR_STATUS_FLIP_0                 3       /* flip head A */
@@ -118,8 +116,6 @@ struct ps3fb_priv {
        unsigned int irq_no;
 
        u64 context_handle, memory_handle;
-       void *xdr_ea;
-       size_t xdr_size;
        struct gpu_driver_info *dinfo;
 
        u64 vblank_count;       /* frame count */
@@ -136,42 +132,19 @@ static struct ps3fb_priv ps3fb;
 struct ps3fb_par {
        u32 pseudo_palette[16];
        int mode_id, new_mode_id;
-       int res_index;
        unsigned int num_frames;        /* num of frame buffers */
        unsigned int width;
        unsigned int height;
-       unsigned long full_offset;      /* start of fullscreen DDR fb */
-       unsigned long fb_offset;        /* start of actual DDR fb */
-       unsigned long pan_offset;
+       unsigned int ddr_line_length;
+       unsigned int ddr_frame_size;
+       unsigned int xdr_frame_size;
+       unsigned int full_offset;       /* start of fullscreen DDR fb */
+       unsigned int fb_offset;         /* start of actual DDR fb */
+       unsigned int pan_offset;
 };
 
-struct ps3fb_res_table {
-       u32 xres;
-       u32 yres;
-       u32 xoff;
-       u32 yoff;
-       u32 type;
-};
-#define PS3FB_RES_FULL 1
-static const struct ps3fb_res_table ps3fb_res[] = {
-       /* res_x,y   margin_x,y  full */
-       {  720,  480,  72,  48 , 0},
-       {  720,  576,  72,  58 , 0},
-       { 1280,  720,  78,  38 , 0},
-       { 1920, 1080, 116,  58 , 0},
-       /* full mode */
-       {  720,  480,   0,   0 , PS3FB_RES_FULL},
-       {  720,  576,   0,   0 , PS3FB_RES_FULL},
-       { 1280,  720,   0,   0 , PS3FB_RES_FULL},
-       { 1920, 1080,   0,   0 , PS3FB_RES_FULL},
-       /* vesa: normally full mode */
-       { 1280,  768,   0,   0 , 0},
-       { 1280, 1024,   0,   0 , 0},
-       { 1920, 1200,   0,   0 , 0},
-       {    0,    0,   0,   0 , 0} };
-
-/* default resolution */
-#define GPU_RES_INDEX  0               /* 720 x 480 */
+
+#define FIRST_NATIVE_MODE_INDEX        10
 
 static const struct fb_videomode ps3fb_modedb[] = {
     /* 60 Hz broadcast modes (modes "1" to "5") */
@@ -211,7 +184,7 @@ static const struct fb_videomode ps3fb_modedb[] = {
         "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5,
         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
     },    {
-        /* 1080 */
+        /* 1080i */
         "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5,
         FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
     },    {
@@ -220,24 +193,7 @@ static const struct fb_videomode ps3fb_modedb[] = {
         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
     },
 
-    /* VESA modes (modes "11" to "13") */
-    {
-       /* WXGA */
-       "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
-       0, FB_VMODE_NONINTERLACED,
-       FB_MODE_IS_VESA
-    }, {
-       /* SXGA */
-       "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
-       FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
-       FB_MODE_IS_VESA
-    }, {
-       /* WUXGA */
-       "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
-       FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
-       FB_MODE_IS_VESA
-    },
-
+    [FIRST_NATIVE_MODE_INDEX] =
     /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
     {
        /* 480if */
@@ -276,12 +232,30 @@ static const struct fb_videomode ps3fb_modedb[] = {
        FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
     }, {
        /* 1080if */
-       "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
+       "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
        FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
     }, {
        /* 1080pf */
        "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
        FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+    },
+
+    /* VESA modes (modes "11" to "13") */
+    {
+       /* WXGA */
+       "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
+       0, FB_VMODE_NONINTERLACED,
+       FB_MODE_IS_VESA
+    }, {
+       /* SXGA */
+       "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+       FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
+       FB_MODE_IS_VESA
+    }, {
+       /* WUXGA */
+       "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
+       FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
+       FB_MODE_IS_VESA
     }
 };
 
@@ -289,110 +263,188 @@ static const struct fb_videomode ps3fb_modedb[] = {
 #define HEAD_A
 #define HEAD_B
 
-#define X_OFF(i)       (ps3fb_res[i].xoff)     /* left/right margin (pixel) */
-#define Y_OFF(i)       (ps3fb_res[i].yoff)     /* top/bottom margin (pixel) */
-#define WIDTH(i)       (ps3fb_res[i].xres)     /* width of FB */
-#define HEIGHT(i)      (ps3fb_res[i].yres)     /* height of FB */
 #define BPP            4                       /* number of bytes per pixel */
 
-/* Start of the virtual frame buffer (relative to fullscreen ) */
-#define VP_OFF(i)      ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
-
 
 static int ps3fb_mode;
 module_param(ps3fb_mode, int, 0);
 
 static char *mode_option __devinitdata;
 
-static int ps3fb_get_res_table(u32 xres, u32 yres, int mode)
+static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
+                         const struct fb_var_screeninfo *var)
 {
-       int full_mode;
-       unsigned int i;
-       u32 x, y, f;
-
-       full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
-       for (i = 0;; i++) {
-               x = ps3fb_res[i].xres;
-               y = ps3fb_res[i].yres;
-               f = ps3fb_res[i].type;
-
-               if (!x) {
-                       pr_debug("ERROR: ps3fb_get_res_table()\n");
-                       return -1;
-               }
+       long xres, yres, left_margin, right_margin, upper_margin, lower_margin;
+       long dx, dy;
+
+       /* maximum values */
+       if (var->xres > vmode->xres || var->yres > vmode->yres ||
+           var->pixclock > vmode->pixclock ||
+           var->hsync_len > vmode->hsync_len ||
+           var->vsync_len > vmode->vsync_len)
+               return -1;
 
-               if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL)
-                       continue;
+       /* progressive/interlaced must match */
+       if ((var->vmode & FB_VMODE_MASK) != vmode->vmode)
+               return -1;
 
-               if (x == xres && (yres == 0 || y == yres))
-                       break;
+       /* minimum resolution */
+       xres = max(var->xres, 1U);
+       yres = max(var->yres, 1U);
+
+       /* minimum margins */
+       left_margin = max(var->left_margin, vmode->left_margin);
+       right_margin = max(var->right_margin, vmode->right_margin);
+       upper_margin = max(var->upper_margin, vmode->upper_margin);
+       lower_margin = max(var->lower_margin, vmode->lower_margin);
+
+       /* resolution + margins may not exceed native parameters */
+       dx = ((long)vmode->left_margin + (long)vmode->xres +
+             (long)vmode->right_margin) -
+            (left_margin + xres + right_margin);
+       if (dx < 0)
+               return -1;
 
-               x = x - 2 * ps3fb_res[i].xoff;
-               y = y - 2 * ps3fb_res[i].yoff;
-               if (x == xres && (yres == 0 || y == yres))
-                       break;
+       dy = ((long)vmode->upper_margin + (long)vmode->yres +
+             (long)vmode->lower_margin) -
+            (upper_margin + yres + lower_margin);
+       if (dy < 0)
+               return -1;
+
+       /* exact match */
+       if (!dx && !dy)
+               return 0;
+
+       /* resolution difference */
+       return (vmode->xres - xres) * (vmode->yres - yres);
+}
+
+static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id)
+{
+       return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1];
+}
+
+static const struct fb_videomode *ps3fb_vmode(int id)
+{
+       u32 mode = id & PS3AV_MODE_MASK;
+
+       if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA)
+               return NULL;
+
+       if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) {
+               /* Non-fullscreen broadcast mode */
+               return &ps3fb_modedb[mode - 1];
        }
-       return i;
+
+       return ps3fb_native_vmode(mode);
 }
 
-static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
+static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var,
                                    u32 *ddr_line_length, u32 *xdr_line_length)
 {
-       unsigned int i, mode;
-
-       for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++)
-               if (var->xres == ps3fb_modedb[i].xres &&
-                   var->yres == ps3fb_modedb[i].yres &&
-                   var->pixclock == ps3fb_modedb[i].pixclock &&
-                   var->hsync_len == ps3fb_modedb[i].hsync_len &&
-                   var->vsync_len == ps3fb_modedb[i].vsync_len &&
-                   var->left_margin == ps3fb_modedb[i].left_margin &&
-                   var->right_margin == ps3fb_modedb[i].right_margin &&
-                   var->upper_margin == ps3fb_modedb[i].upper_margin &&
-                   var->lower_margin == ps3fb_modedb[i].lower_margin &&
-                   var->sync == ps3fb_modedb[i].sync &&
-                   (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode)
-                       goto found;
-
-       pr_debug("ps3fb_find_mode: mode not found\n");
-       return 0;
+       unsigned int id, best_id;
+       int diff, best_diff;
+       const struct fb_videomode *vmode;
+       long gap;
+
+       best_id = 0;
+       best_diff = INT_MAX;
+       pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__,
+                var->left_margin, var->xres, var->right_margin,
+                var->upper_margin, var->yres, var->lower_margin);
+       for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) {
+               vmode = ps3fb_native_vmode(id);
+               diff = ps3fb_cmp_mode(vmode, var);
+               pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n",
+                        __func__, id, vmode->left_margin, vmode->xres,
+                        vmode->right_margin, vmode->upper_margin,
+                        vmode->yres, vmode->lower_margin, diff);
+               if (diff < 0)
+                       continue;
+               if (diff < best_diff) {
+                       best_id = id;
+                       if (!diff)
+                               break;
+                       best_diff = diff;
+               }
+       }
 
-found:
-       /* Cropped broadcast modes use the full line length */
-       *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP;
+       if (!best_id) {
+               pr_debug("%s: no suitable mode found\n", __func__);
+               return 0;
+       }
 
-       if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
-               *xdr_line_length = GPU_ALIGN_UP(max(var->xres,
-                                                   var->xres_virtual) * BPP);
-               if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
-                       *xdr_line_length = GPU_MAX_LINE_LENGTH;
-       } else
-               *xdr_line_length = *ddr_line_length;
+       id = best_id;
+       vmode = ps3fb_native_vmode(id);
 
-       /* Full broadcast modes have the full mode bit set */
-       mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
+       *ddr_line_length = vmode->xres * BPP;
 
-       pr_debug("ps3fb_find_mode: mode %u\n", mode);
+       /* minimum resolution */
+       if (!var->xres)
+               var->xres = 1;
+       if (!var->yres)
+               var->yres = 1;
 
-       return mode;
-}
+       /* minimum virtual resolution */
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
 
-static const struct fb_videomode *ps3fb_default_mode(int id)
-{
-       u32 mode = id & PS3AV_MODE_MASK;
-       u32 flags;
+       /* minimum margins */
+       if (var->left_margin < vmode->left_margin)
+               var->left_margin = vmode->left_margin;
+       if (var->right_margin < vmode->right_margin)
+               var->right_margin = vmode->right_margin;
+       if (var->upper_margin < vmode->upper_margin)
+               var->upper_margin = vmode->upper_margin;
+       if (var->lower_margin < vmode->lower_margin)
+               var->lower_margin = vmode->lower_margin;
+
+       /* extra margins */
+       gap = ((long)vmode->left_margin + (long)vmode->xres +
+              (long)vmode->right_margin) -
+             ((long)var->left_margin + (long)var->xres +
+              (long)var->right_margin);
+       if (gap > 0) {
+               var->left_margin += gap/2;
+               var->right_margin += (gap+1)/2;
+               pr_debug("%s: rounded up H to %u [%u] %u\n", __func__,
+                        var->left_margin, var->xres, var->right_margin);
+       }
 
-       if (mode < 1 || mode > 13)
-               return NULL;
+       gap = ((long)vmode->upper_margin + (long)vmode->yres +
+              (long)vmode->lower_margin) -
+             ((long)var->upper_margin + (long)var->yres +
+              (long)var->lower_margin);
+       if (gap > 0) {
+               var->upper_margin += gap/2;
+               var->lower_margin += (gap+1)/2;
+               pr_debug("%s: rounded up V to %u [%u] %u\n", __func__,
+                        var->upper_margin, var->yres, var->lower_margin);
+       }
+
+       /* fixed fields */
+       var->pixclock = vmode->pixclock;
+       var->hsync_len = vmode->hsync_len;
+       var->vsync_len = vmode->vsync_len;
+       var->sync = vmode->sync;
 
-       flags = id & ~PS3AV_MODE_MASK;
+       if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
+               *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP);
+               if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
+                       *xdr_line_length = GPU_MAX_LINE_LENGTH;
+       } else
+               *xdr_line_length = *ddr_line_length;
 
-       if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
-               /* Full broadcast mode */
-               return &ps3fb_modedb[mode + 12];
+       if (vmode->sync & FB_SYNC_BROADCAST) {
+               /* Full broadcast modes have the full mode bit set */
+               if (vmode->xres == var->xres && vmode->yres == var->yres)
+                       id |= PS3AV_MODE_FULL;
        }
 
-       return &ps3fb_modedb[mode - 1];
+       pr_debug("%s: mode %u\n", __func__, id);
+       return id;
 }
 
 static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
@@ -439,8 +491,7 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
 static int ps3fb_sync(struct fb_info *info, u32 frame)
 {
        struct ps3fb_par *par = info->par;
-       int i, error = 0;
-       u32 ddr_line_length, xdr_line_length;
+       int error = 0;
        u64 ddr_base, xdr_base;
 
        if (frame > par->num_frames - 1) {
@@ -450,16 +501,13 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
                goto out;
        }
 
-       i = par->res_index;
-       xdr_line_length = info->fix.line_length;
-       ddr_line_length = ps3fb_res[i].xres * BPP;
-       xdr_base = frame * info->var.yres_virtual * xdr_line_length;
-       ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;
+       xdr_base = frame * par->xdr_frame_size;
+       ddr_base = frame * par->ddr_frame_size;
 
        ps3fb_sync_image(info->device, ddr_base + par->full_offset,
                         ddr_base + par->fb_offset, xdr_base + par->pan_offset,
-                        par->width, par->height, ddr_line_length,
-                        xdr_line_length);
+                        par->width, par->height, par->ddr_line_length,
+                        info->fix.line_length);
 
 out:
        return error;
@@ -498,22 +546,11 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        u32 xdr_line_length, ddr_line_length;
        int mode;
 
-       dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,
-               info->var.xres);
-       dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres,
-               info->var.yres);
-
-       /* FIXME For now we do exact matches only */
        mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);
        if (!mode)
                return -EINVAL;
 
        /* Virtual screen */
-       if (var->xres_virtual < var->xres)
-               var->xres_virtual = var->xres;
-       if (var->yres_virtual < var->yres)
-               var->yres_virtual = var->yres;
-
        if (var->xres_virtual > xdr_line_length / BPP) {
                dev_dbg(info->device,
                        "Horizontal virtual screen size too large\n");
@@ -559,7 +596,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        }
 
        /* Memory limit */
-       if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) {
+       if (var->yres_virtual * xdr_line_length > info->fix.smem_len) {
                dev_dbg(info->device, "Not enough memory\n");
                return -ENOMEM;
        }
@@ -578,39 +615,38 @@ static int ps3fb_set_par(struct fb_info *info)
 {
        struct ps3fb_par *par = info->par;
        unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
-       int i;
-       unsigned long offset;
+       unsigned int ddr_xoff, ddr_yoff, offset;
+       const struct fb_videomode *vmode;
        u64 dst;
 
-       dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
-               info->var.xres, info->var.xres_virtual,
-               info->var.yres, info->var.yres_virtual, info->var.pixclock);
-
        mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);
        if (!mode)
                return -EINVAL;
 
-       i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
-       par->res_index = i;
+       vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK);
 
-       info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
-       info->fix.smem_len = ps3fb.xdr_size;
        info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
        info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
        info->fix.line_length = xdr_line_length;
 
-       info->screen_base = (char __iomem *)ps3fb.xdr_ea;
+       par->ddr_line_length = ddr_line_length;
+       par->ddr_frame_size = vmode->yres * ddr_line_length;
+       par->xdr_frame_size = info->var.yres_virtual * xdr_line_length;
 
-       par->num_frames = ps3fb.xdr_size /
-                         max(ps3fb_res[i].yres * ddr_line_length,
-                             info->var.yres_virtual * xdr_line_length);
+       par->num_frames = info->fix.smem_len /
+                         max(par->ddr_frame_size, par->xdr_frame_size);
 
        /* Keep the special bits we cannot set using fb_var_screeninfo */
        par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
 
        par->width = info->var.xres;
        par->height = info->var.yres;
-       offset = VP_OFF(i);
+
+       /* Start of the virtual frame buffer (relative to fullscreen) */
+       ddr_xoff = info->var.left_margin - vmode->left_margin;
+       ddr_yoff = info->var.upper_margin - vmode->upper_margin;
+       offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP;
+
        par->fb_offset = GPU_ALIGN_UP(offset);
        par->full_offset = par->fb_offset - offset;
        par->pan_offset = info->var.yoffset * xdr_line_length +
@@ -625,16 +661,16 @@ static int ps3fb_set_par(struct fb_info *info)
        }
 
        /* Clear XDR frame buffer memory */
-       memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
+       memset((void __force *)info->screen_base, 0, info->fix.smem_len);
 
        /* Clear DDR frame buffer memory */
-       lines = ps3fb_res[i].yres * par->num_frames;
+       lines = vmode->yres * par->num_frames;
        if (par->full_offset)
                lines++;
-       maxlines = ps3fb.xdr_size / ddr_line_length;
+       maxlines = info->fix.smem_len / ddr_line_length;
        for (dst = 0; lines; dst += maxlines * ddr_line_length) {
                unsigned int l = min(lines, maxlines);
-               ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
+               ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l,
                                 ddr_line_length, ddr_line_length);
                lines -= l;
        }
@@ -797,7 +833,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
        case PS3FB_IOCTL_SETMODE:
                {
                        struct ps3fb_par *par = info->par;
-                       const struct fb_videomode *mode;
+                       const struct fb_videomode *vmode;
                        struct fb_var_screeninfo var;
 
                        if (copy_from_user(&val, argp, sizeof(val)))
@@ -810,10 +846,10 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        }
                        dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
                        retval = -EINVAL;
-                       mode = ps3fb_default_mode(val);
-                       if (mode) {
+                       vmode = ps3fb_vmode(val);
+                       if (vmode) {
                                var = info->var;
-                               fb_videomode_to_var(&var, mode);
+                               fb_videomode_to_var(&var, vmode);
                                acquire_console_sem();
                                info->flags |= FBINFO_MISC_USEREVENT;
                                /* Force, in case only special bits changed */
@@ -975,10 +1011,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
                        __func__, status);
                return -ENXIO;
        }
-       dev_dbg(dev,
-               "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
-               ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar,
-               virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size);
+       dev_dbg(dev, "video:%p ioif:%lx lpar:%lx size:%lx\n",
+               ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
+               ps3fb_videomemory.size);
 
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
@@ -1055,14 +1090,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        struct fb_info *info;
        struct ps3fb_par *par;
        int retval = -ENOMEM;
-       u32 xres, yres;
        u64 ddr_lpar = 0;
        u64 lpar_dma_control = 0;
        u64 lpar_driver_info = 0;
        u64 lpar_reports = 0;
        u64 lpar_reports_size = 0;
        u64 xdr_lpar;
-       int status, res_index;
+       void *fb_start;
+       int status;
        struct task_struct *task;
        unsigned long max_ps3fb_size;
 
@@ -1080,14 +1115,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 
        if (!ps3fb_mode)
                ps3fb_mode = ps3av_get_mode();
-       dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode);
-
-       if (ps3fb_mode > 0 &&
-           !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
-               res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
-               dev_dbg(&dev->core, "res_index:%d\n", res_index);
-       } else
-               res_index = GPU_RES_INDEX;
+       dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode);
 
        atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
        atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
@@ -1124,7 +1152,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        }
 
        /* vsync interrupt */
-       ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
+       ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
        if (!ps3fb.dinfo) {
                dev_err(&dev->core, "%s: ioremap failed\n", __func__);
                goto err_gpu_context_free;
@@ -1134,22 +1162,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        if (retval)
                goto err_iounmap_dinfo;
 
-       /* XDR frame buffer */
-       ps3fb.xdr_ea = ps3fb_videomemory.address;
-       xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea));
-
        /* Clear memory to prevent kernel info leakage into userspace */
-       memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
-
-       /*
-        * The GPU command buffer is at the start of video memory
-        * As we don't use the full command buffer, we can put the actual
-        * frame buffer at offset GPU_FB_START and save some precious XDR
-        * memory
-        */
-       ps3fb.xdr_ea += GPU_FB_START;
-       ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START;
+       memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
 
+       xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
        retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
        if (retval)
                goto err_free_irq;
@@ -1161,15 +1177,22 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        par = info->par;
        par->mode_id = ~ps3fb_mode;     /* != ps3fb_mode, to trigger change */
        par->new_mode_id = ps3fb_mode;
-       par->res_index = res_index;
        par->num_frames = 1;
 
-       info->screen_base = (char __iomem *)ps3fb.xdr_ea;
        info->fbops = &ps3fb_ops;
-
        info->fix = ps3fb_fix;
-       info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
-       info->fix.smem_len = ps3fb.xdr_size;
+
+       /*
+        * The GPU command buffer is at the start of video memory
+        * As we don't use the full command buffer, we can put the actual
+        * frame buffer at offset GPU_FB_START and save some precious XDR
+        * memory
+        */
+       fb_start = ps3fb_videomemory.address + GPU_FB_START;
+       info->screen_base = (char __force __iomem *)fb_start;
+       info->fix.smem_start = virt_to_abs(fb_start);
+       info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START;
+
        info->pseudo_palette = par->pseudo_palette;
        info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
                      FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
@@ -1180,7 +1203,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 
        if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
                          ARRAY_SIZE(ps3fb_modedb),
-                         ps3fb_default_mode(par->new_mode_id), 32)) {
+                         ps3fb_vmode(par->new_mode_id), 32)) {
                retval = -EINVAL;
                goto err_fb_dealloc;
        }
@@ -1194,9 +1217,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 
        dev->core.driver_data = info;
 
-       dev_info(info->device, "%s %s, using %lu KiB of video memory\n",
+       dev_info(info->device, "%s %s, using %u KiB of video memory\n",
                 dev_driver_string(info->dev), info->dev->bus_id,
-                ps3fb.xdr_size >> 10);
+                info->fix.smem_len >> 10);
 
        task = kthread_run(ps3fbd, info, DEVICE_NAME);
        if (IS_ERR(task)) {
@@ -1219,7 +1242,7 @@ err_free_irq:
        free_irq(ps3fb.irq_no, &dev->core);
        ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
-       iounmap((u8 __iomem *)ps3fb.dinfo);
+       iounmap((u8 __force __iomem *)ps3fb.dinfo);
 err_gpu_context_free:
        lv1_gpu_context_free(ps3fb.context_handle);
 err_gpu_memory_free:
@@ -1254,7 +1277,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
                framebuffer_release(info);
                info = dev->core.driver_data = NULL;
        }
-       iounmap((u8 __iomem *)ps3fb.dinfo);
+       iounmap((u8 __force __iomem *)ps3fb.dinfo);
 
        status = lv1_gpu_context_free(ps3fb.context_handle);
        if (status)
index b3c31d9..71fa6ed 100644 (file)
@@ -110,6 +110,11 @@ static int debug   = 0;
 
 /* useful functions */
 
+static int is_s3c2412(struct s3c2410fb_info *fbi)
+{
+       return (fbi->drv_type == DRV_S3C2412);
+}
+
 /* s3c2410fb_set_lcdaddr
  *
  * initialise lcd controller address pointers
@@ -501,7 +506,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
 {
        unsigned long flags;
        unsigned long irqen;
-       void __iomem *regs = fbi->io;
+       void __iomem *irq_base = fbi->irq_base;
 
        local_irq_save(flags);
 
@@ -511,9 +516,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
                fbi->palette_ready = 1;
 
                /* enable IRQ */
-               irqen = readl(regs + S3C2410_LCDINTMSK);
+               irqen = readl(irq_base + S3C24XX_LCDINTMSK);
                irqen &= ~S3C2410_LCDINT_FRSYNC;
-               writel(irqen, regs + S3C2410_LCDINTMSK);
+               writel(irqen, irq_base + S3C24XX_LCDINTMSK);
        }
 
        local_irq_restore(flags);
@@ -594,15 +599,17 @@ static int s3c2410fb_setcolreg(unsigned regno,
 static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
 {
        struct s3c2410fb_info *fbi = info->par;
-       void __iomem *regs = fbi->io;
+       void __iomem *tpal_reg = fbi->io;
 
        dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
 
+       tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
+
        if (blank_mode == FB_BLANK_UNBLANK)
-               writel(0x0, regs + S3C2410_TPAL);
+               writel(0x0, tpal_reg);
        else {
                dprintk("setting TPAL to output 0x000000\n");
-               writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
+               writel(S3C2410_TPAL_EN, tpal_reg);
        }
 
        return 0;
@@ -663,7 +670,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
        dma_addr_t map_dma;
        unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
 
-       dprintk("map_video_memory(fbi=%p)\n", fbi);
+       dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
 
        info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
                                                   &map_dma, GFP_KERNEL);
@@ -672,7 +679,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info)
                /* prevent initial garbage on screen */
                dprintk("map_video_memory: clear %p:%08x\n",
                        info->screen_base, map_size);
-               memset(info->screen_base, 0xf0, map_size);
+               memset(info->screen_base, 0x00, map_size);
 
                info->fix.smem_start = map_dma;
 
@@ -709,6 +716,16 @@ static int s3c2410fb_init_registers(struct fb_info *info)
        struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
        unsigned long flags;
        void __iomem *regs = fbi->io;
+       void __iomem *tpal;
+       void __iomem *lpcsel;
+
+       if (is_s3c2412(fbi)) {
+               tpal = regs + S3C2412_TPAL;
+               lpcsel = regs + S3C2412_TCONSEL;
+       } else {
+               tpal = regs + S3C2410_TPAL;
+               lpcsel = regs + S3C2410_LPCSEL;
+       }
 
        /* Initialise LCD with values from haret */
 
@@ -724,12 +741,12 @@ static int s3c2410fb_init_registers(struct fb_info *info)
        local_irq_restore(flags);
 
        dprintk("LPCSEL    = 0x%08lx\n", mach_info->lpcsel);
-       writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
+       writel(mach_info->lpcsel, lpcsel);
 
-       dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
+       dprintk("replacing TPAL %08x\n", readl(tpal));
 
        /* ensure temporary palette disabled */
-       writel(0x00, regs + S3C2410_TPAL);
+       writel(0x00, tpal);
 
        return 0;
 }
@@ -763,15 +780,15 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
 static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 {
        struct s3c2410fb_info *fbi = dev_id;
-       void __iomem *regs = fbi->io;
-       unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
+       void __iomem *irq_base = fbi->irq_base;
+       unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND);
 
        if (lcdirq & S3C2410_LCDINT_FRSYNC) {
                if (fbi->palette_ready)
                        s3c2410fb_write_palette(fbi);
 
-               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
-               writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
+               writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND);
+               writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND);
        }
 
        return IRQ_HANDLED;
@@ -779,7 +796,8 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 
 static char driver_name[] = "s3c2410fb";
 
-static int __init s3c2410fb_probe(struct platform_device *pdev)
+static int __init s3c24xxfb_probe(struct platform_device *pdev,
+                                 enum s3c_drv_type drv_type)
 {
        struct s3c2410fb_info *info;
        struct s3c2410fb_display *display;
@@ -799,6 +817,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       if (mach_info->default_display >= mach_info->num_displays) {
+               dev_err(&pdev->dev, "default is %d but only %d displays\n",
+                       mach_info->default_display, mach_info->num_displays);
+               return -EINVAL;
+       }
+
        display = mach_info->displays + mach_info->default_display;
 
        irq = platform_get_irq(pdev, 0);
@@ -815,6 +839,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
 
        info = fbinfo->par;
        info->dev = &pdev->dev;
+       info->drv_type = drv_type;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
@@ -838,6 +863,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
                goto release_mem;
        }
 
+       info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
+
        dprintk("devinit\n");
 
        strcpy(fbinfo->fix.id, driver_name);
@@ -946,6 +973,16 @@ dealloc_fb:
        return ret;
 }
 
+static int __init s3c2410fb_probe(struct platform_device *pdev)
+{
+       return s3c24xxfb_probe(pdev, DRV_S3C2410);
+}
+
+static int __init s3c2412fb_probe(struct platform_device *pdev)
+{
+       return s3c24xxfb_probe(pdev, DRV_S3C2412);
+}
+
 /* s3c2410fb_stop_lcd
  *
  * shutdown the lcd controller
@@ -1047,14 +1084,31 @@ static struct platform_driver s3c2410fb_driver = {
        },
 };
 
+static struct platform_driver s3c2412fb_driver = {
+       .probe          = s3c2412fb_probe,
+       .remove         = s3c2410fb_remove,
+       .suspend        = s3c2410fb_suspend,
+       .resume         = s3c2410fb_resume,
+       .driver         = {
+               .name   = "s3c2412-lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
 int __init s3c2410fb_init(void)
 {
-       return platform_driver_register(&s3c2410fb_driver);
+       int ret = platform_driver_register(&s3c2410fb_driver);
+
+       if (ret == 0)
+               ret = platform_driver_register(&s3c2412fb_driver);;
+
+       return ret;
 }
 
 static void __exit s3c2410fb_cleanup(void)
 {
        platform_driver_unregister(&s3c2410fb_driver);
+       platform_driver_unregister(&s3c2412fb_driver);
 }
 
 module_init(s3c2410fb_init);
index 6ce5dc2..dbb73b9 100644 (file)
 #ifndef __S3C2410FB_H
 #define __S3C2410FB_H
 
+enum s3c_drv_type {
+       DRV_S3C2410,
+       DRV_S3C2412,
+};
+
 struct s3c2410fb_info {
        struct device           *dev;
        struct clk              *clk;
 
        struct resource         *mem;
        void __iomem            *io;
+       void __iomem            *irq_base;
 
+       enum s3c_drv_type       drv_type;
        struct s3c2410fb_hw     regs;
 
        unsigned int            palette_ready;
index 93ae747..7380362 100644 (file)
@@ -427,7 +427,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 
        monitor->feature = buffer[0x18];
 
-       if(!buffer[0x14] & 0x80) {
+       if(!(buffer[0x14] & 0x80)) {
                if(!(buffer[0x14] & 0x08)) {
                        printk(KERN_INFO
                                "sisfb: WARNING: Monitor does not support separate syncs\n");
@@ -4621,9 +4621,9 @@ sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
 
        while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
                temp = pdev->vendor;
-               pci_dev_put(pdev);
                if(temp == pcivendor) {
                        ret = 1;
+                       pci_dev_put(pdev);
                        break;
                }
        }
index 58f200c..e83dfba 100644 (file)
@@ -641,6 +641,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
 {
        unsigned long control;
        void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
+       struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
 
        control = readl(ctrl_reg);
 
@@ -657,26 +658,34 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
                sm501fb_sync_regs(fbi);
                mdelay(10);
 
-               control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
-               writel(control, ctrl_reg);
-               sm501fb_sync_regs(fbi);
-               mdelay(10);
-
-               control |= SM501_DC_PANEL_CONTROL_FPEN;
-               writel(control, ctrl_reg);
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+                       control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
 
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+                       control |= SM501_DC_PANEL_CONTROL_FPEN;
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
        } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
                /* disable panel power */
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+                       control &= ~SM501_DC_PANEL_CONTROL_FPEN;
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
 
-               control &= ~SM501_DC_PANEL_CONTROL_FPEN;
-               writel(control, ctrl_reg);
-               sm501fb_sync_regs(fbi);
-               mdelay(10);
-
-               control &= ~SM501_DC_PANEL_CONTROL_BIAS;
-               writel(control, ctrl_reg);
-               sm501fb_sync_regs(fbi);
-               mdelay(10);
+               if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+                       control &= ~SM501_DC_PANEL_CONTROL_BIAS;
+                       writel(control, ctrl_reg);
+                       sm501fb_sync_regs(fbi);
+                       mdelay(10);
+               }
 
                control &= ~SM501_DC_PANEL_CONTROL_DATA;
                writel(control, ctrl_reg);
@@ -1267,6 +1276,7 @@ static int sm501fb_start(struct sm501fb_info *info,
 {
        struct resource *res;
        struct device *dev;
+       int k;
        int ret;
 
        info->dev = dev = &pdev->dev;
@@ -1328,6 +1338,13 @@ static int sm501fb_start(struct sm501fb_info *info,
 
        info->fbmem_len = (res->end - res->start)+1;
 
+       /* clear framebuffer memory - avoids garbage data on unused fb */
+       memset(info->fbmem, 0, info->fbmem_len);
+
+       /* clear palette ram - undefined at power on */
+       for (k = 0; k < (256 * 3); k++)
+               writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
+
        /* enable display controller */
        sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
 
@@ -1681,6 +1698,15 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
        if (par->screen.size == 0)
                return 0;
 
+       /* blank the relevant interface to ensure unit power minimised */
+       (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+
+       /* tell console/fb driver we are suspending */
+
+       acquire_console_sem();
+       fb_set_suspend(fbi, 1);
+       release_console_sem();
+
        /* backup copies in case chip is powered down over suspend */
 
        par->store_fb = vmalloc(par->screen.size);
@@ -1700,12 +1726,6 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
 
        memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
        memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
-       /* blank the relevant interface to ensure unit power minimised */
-       (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
-
-       acquire_console_sem();
-       fb_set_suspend(fbi, 1);
-       release_console_sem();
 
        return 0;
 
index 057bdd5..71e179e 100644 (file)
@@ -1342,7 +1342,7 @@ out_err:
 }
 
 #ifndef MODULE
-static void tdfxfb_setup(char *options)
+static void __init tdfxfb_setup(char *options)
 {
        char *this_opt;
 
index a14ef89..be27b9c 100644 (file)
@@ -2003,12 +2003,12 @@ static void __devexit uvesafb_exit(void)
 
 module_exit(uvesafb_exit);
 
-static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
+static int param_get_scroll(char *buffer, struct kernel_param *kp)
 {
        return 0;
 }
 
-static inline int param_set_scroll(const char *val, struct kernel_param *kp)
+static int param_set_scroll(const char *val, struct kernel_param *kp)
 {
        ypan = 0;
 
@@ -2022,11 +2022,11 @@ static inline int param_set_scroll(const char *val, struct kernel_param *kp)
        return 0;
 }
 
-#define param_check_scroll(name, p) __param_check(name, p, void);
+#define param_check_scroll(name, p) __param_check(name, p, void)
 
 module_param_named(scroll, ypan, scroll, 0);
 MODULE_PARM_DESC(scroll,
-       "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'");
+       "Scrolling mode, set to 'redraw', 'ypan', or 'ywrap'");
 module_param_named(vgapal, pmi_setpal, invbool, 0);
 MODULE_PARM_DESC(vgapal, "Set palette using VGA registers");
 module_param_named(pmipal, pmi_setpal, bool, 0);
index 1c65666..2aa71eb 100644 (file)
@@ -651,7 +651,7 @@ static int vmlfb_check_var_locked(struct fb_var_screeninfo *var,
                return -EINVAL;
        }
 
-       pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F);
+       pitch = ALIGN((var->xres * var->bits_per_pixel) >> 3, 0x40);
        mem = pitch * var->yres_virtual;
        if (mem > vinfo->vram_contig_size) {
                return -ENOMEM;
@@ -785,8 +785,7 @@ static int vmlfb_set_par_locked(struct vml_info *vinfo)
        int clock;
 
        vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
-       vinfo->stride =
-           __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F);
+       vinfo->stride = ALIGN(var->xres_virtual * vinfo->bytes_per_pixel, 0x40);
        info->fix.line_length = vinfo->stride;
 
        if (!subsys)
index 8236d44..c449309 100644 (file)
@@ -42,5 +42,15 @@ config W1_MASTER_DS1WM
          in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
          hx4700.
 
+config W1_MASTER_GPIO
+       tristate "GPIO 1-wire busmaster"
+       depends on GENERIC_GPIO
+       help
+         Say Y here if you want to communicate with your 1-wire devices using
+         GPIO pins. This driver uses the GPIO API to control the wire.
+
+         This support is also available as a module.  If so, the module
+         will be called w1-gpio.ko.
+
 endmenu
 
index 11551b3..1420b5b 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_W1_MASTER_MATROX)          += matrox_w1.o
 obj-$(CONFIG_W1_MASTER_DS2490)         += ds2490.o
 obj-$(CONFIG_W1_MASTER_DS2482)         += ds2482.o
 obj-$(CONFIG_W1_MASTER_DS1WM)          += ds1wm.o
+obj-$(CONFIG_W1_MASTER_GPIO)           += w1-gpio.o
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
new file mode 100644 (file)
index 0000000..9e1138a
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * w1-gpio - GPIO w1 bus master driver
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/w1-gpio.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#include <asm/gpio.h>
+
+static void w1_gpio_write_bit_dir(void *data, u8 bit)
+{
+       struct w1_gpio_platform_data *pdata = data;
+
+       if (bit)
+               gpio_direction_input(pdata->pin);
+       else
+               gpio_direction_output(pdata->pin, 0);
+}
+
+static void w1_gpio_write_bit_val(void *data, u8 bit)
+{
+       struct w1_gpio_platform_data *pdata = data;
+
+       gpio_set_value(pdata->pin, bit);
+}
+
+static u8 w1_gpio_read_bit(void *data)
+{
+       struct w1_gpio_platform_data *pdata = data;
+
+       return gpio_get_value(pdata->pin);
+}
+
+static int __init w1_gpio_probe(struct platform_device *pdev)
+{
+       struct w1_bus_master *master;
+       struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+       int err;
+
+       if (!pdata)
+               return -ENXIO;
+
+       master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       err = gpio_request(pdata->pin, "w1");
+       if (err)
+               goto free_master;
+
+       master->data = pdata;
+       master->read_bit = w1_gpio_read_bit;
+
+       if (pdata->is_open_drain) {
+               gpio_direction_output(pdata->pin, 1);
+               master->write_bit = w1_gpio_write_bit_val;
+       } else {
+               gpio_direction_input(pdata->pin);
+               master->write_bit = w1_gpio_write_bit_dir;
+       }
+
+       err = w1_add_master_device(master);
+       if (err)
+               goto free_gpio;
+
+       platform_set_drvdata(pdev, master);
+
+       return 0;
+
+ free_gpio:
+       gpio_free(pdata->pin);
+ free_master:
+       kfree(master);
+
+       return err;
+}
+
+static int __exit w1_gpio_remove(struct platform_device *pdev)
+{
+       struct w1_bus_master *master = platform_get_drvdata(pdev);
+       struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+
+       w1_remove_master_device(master);
+       gpio_free(pdata->pin);
+       kfree(master);
+
+       return 0;
+}
+
+static struct platform_driver w1_gpio_driver = {
+       .driver = {
+               .name   = "w1-gpio",
+               .owner  = THIS_MODULE,
+       },
+       .remove = __exit_p(w1_gpio_remove),
+};
+
+static int __init w1_gpio_init(void)
+{
+       return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe);
+}
+
+static void __exit w1_gpio_exit(void)
+{
+       platform_driver_unregister(&w1_gpio_driver);
+}
+
+module_init(w1_gpio_init);
+module_exit(w1_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO w1 bus master driver");
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
index 112f4ec..fb28aca 100644 (file)
@@ -92,6 +92,7 @@ struct w1_therm_family_converter
        int                     (*convert)(u8 rom[9]);
 };
 
+/* The return value is millidegrees Centigrade. */
 static inline int w1_DS18B20_convert_temp(u8 rom[9]);
 static inline int w1_DS18S20_convert_temp(u8 rom[9]);
 
@@ -113,7 +114,7 @@ static struct w1_therm_family_converter w1_therm_families[] = {
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
 {
        s16 t = (rom[1] << 8) | rom[0];
-       t /= 16;
+       t = t*1000/16;
        return t;
 }
 
index 33e5031..7293c9b 100644 (file)
@@ -675,7 +675,6 @@ static void w1_slave_found(void *data, u64 rn)
        struct w1_slave *sl;
        struct list_head *ent;
        struct w1_reg_num *tmp;
-       int family_found = 0;
        struct w1_master *dev;
        u64 rn_le = cpu_to_le64(rn);
 
@@ -698,9 +697,6 @@ static void w1_slave_found(void *data, u64 rn)
                    sl->reg_num.crc == tmp->crc) {
                        set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
                        break;
-               } else if (sl->reg_num.family == tmp->family) {
-                       family_found = 1;
-                       break;
                }
 
                slave_count++;
index e48a630..e63067d 100644 (file)
@@ -534,7 +534,6 @@ void __init bdev_cache_init(void)
        if (err)
                panic("Cannot register bdev pseudo-fs");
        bd_mnt = kern_mount(&bd_type);
-       err = PTR_ERR(bd_mnt);
        if (IS_ERR(bd_mnt))
                panic("Cannot create bdev pseudo-fs");
        blockdev_superblock = bd_mnt->mnt_sb;   /* For writeback */
index 69baca5..ee80ff3 100644 (file)
@@ -2083,51 +2083,6 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
 
 #ifdef CONFIG_EPOLL
 
-#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
-asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd,
-                       struct compat_epoll_event __user *event)
-{
-       long err = 0;
-       struct compat_epoll_event user;
-       struct epoll_event __user *kernel = NULL;
-
-       if (event) {
-               if (copy_from_user(&user, event, sizeof(user)))
-                       return -EFAULT;
-               kernel = compat_alloc_user_space(sizeof(struct epoll_event));
-               err |= __put_user(user.events, &kernel->events);
-               err |= __put_user(user.data, &kernel->data);
-       }
-
-       return err ? err : sys_epoll_ctl(epfd, op, fd, kernel);
-}
-
-
-asmlinkage long compat_sys_epoll_wait(int epfd,
-                       struct compat_epoll_event __user *events,
-                       int maxevents, int timeout)
-{
-       long i, ret, err = 0;
-       struct epoll_event __user *kbuf;
-       struct epoll_event ev;
-
-       if ((maxevents <= 0) ||
-                       (maxevents > (INT_MAX / sizeof(struct epoll_event))))
-               return -EINVAL;
-       kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents);
-       ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout);
-       for (i = 0; i < ret; i++) {
-               err |= __get_user(ev.events, &kbuf[i].events);
-               err |= __get_user(ev.data, &kbuf[i].data);
-               err |= __put_user(ev.events, &events->events);
-               err |= __put_user_unaligned(ev.data, &events->data);
-               events++;
-       }
-
-       return err ? -EFAULT: ret;
-}
-#endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */
-
 #ifdef TIF_RESTORE_SIGMASK
 asmlinkage long compat_sys_epoll_pwait(int epfd,
                        struct compat_epoll_event __user *events,
@@ -2153,11 +2108,7 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
                sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
        }
 
-#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT
-       err = compat_sys_epoll_wait(epfd, events, maxevents, timeout);
-#else
        err = sys_epoll_wait(epfd, events, maxevents, timeout);
-#endif
 
        /*
         * If we changed the signal mask, we need to restore the original one.
index d9ca1e5..44f6cf2 100644 (file)
@@ -89,7 +89,7 @@ static void d_free(struct dentry *dentry)
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
        /* if dentry was never inserted into hash, immediate free is OK */
-       if (dentry->d_hash.pprev == NULL)
+       if (hlist_unhashed(&dentry->d_hash))
                __d_free(dentry);
        else
                call_rcu(&dentry->d_u.d_rcu, d_callback);
@@ -1408,9 +1408,6 @@ void d_delete(struct dentry * dentry)
        if (atomic_read(&dentry->d_count) == 1) {
                dentry_iput(dentry);
                fsnotify_nameremove(dentry, isdir);
-
-               /* remove this and other inotify debug checks after 2.6.18 */
-               dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
                return;
        }
 
index cee7c6f..def4e96 100644 (file)
@@ -696,9 +696,8 @@ static int dqinit_needed(struct inode *inode, int type)
 /* This routine is guarded by dqonoff_mutex mutex */
 static void add_dquot_ref(struct super_block *sb, int type)
 {
-       struct inode *inode;
+       struct inode *inode, *old_inode = NULL;
 
-restart:
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                if (!atomic_read(&inode->i_writecount))
@@ -711,12 +710,18 @@ restart:
                __iget(inode);
                spin_unlock(&inode_lock);
 
+               iput(old_inode);
                sb->dq_op->initialize(inode, type);
-               iput(inode);
-               /* As we may have blocked we had better restart... */
-               goto restart;
+               /* We hold a reference to 'inode' so it couldn't have been
+                * removed from s_inodes list while we dropped the inode_lock.
+                * We cannot iput the inode now as we can be holding the last
+                * reference and we cannot iput it under inode_lock. So we
+                * keep the reference and iput it later. */
+               old_inode = inode;
+               spin_lock(&inode_lock);
        }
        spin_unlock(&inode_lock);
+       iput(old_inode);
 }
 
 /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */
index f8ef0af..a066e10 100644 (file)
@@ -355,8 +355,11 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
        }
        /* Consider doing this once, when the file is opened */
        mutex_lock(&crypt_stat->cs_tfm_mutex);
-       rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
-                                    crypt_stat->key_size);
+       if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
+               rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
+                                            crypt_stat->key_size);
+               crypt_stat->flags |= ECRYPTFS_KEY_SET;
+       }
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
                                rc);
@@ -376,11 +379,10 @@ out:
  *
  * Convert an eCryptfs page index into a lower byte offset
  */
-void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
-                                     struct ecryptfs_crypt_stat *crypt_stat)
+static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
+                                            struct ecryptfs_crypt_stat *crypt_stat)
 {
-       (*offset) = ((crypt_stat->extent_size
-                     * crypt_stat->num_header_extents_at_front)
+       (*offset) = (crypt_stat->num_header_bytes_at_front
                     + (crypt_stat->extent_size * extent_num));
 }
 
@@ -842,15 +844,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
        set_extent_mask_and_shift(crypt_stat);
        crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
        if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
-               crypt_stat->num_header_extents_at_front = 0;
+               crypt_stat->num_header_bytes_at_front = 0;
        else {
                if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
-                       crypt_stat->num_header_extents_at_front =
-                               (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE
-                                / crypt_stat->extent_size);
+                       crypt_stat->num_header_bytes_at_front =
+                               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
                else
-                       crypt_stat->num_header_extents_at_front =
-                               (PAGE_CACHE_SIZE / crypt_stat->extent_size);
+                       crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE;
        }
 }
 
@@ -1128,7 +1128,7 @@ write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
 
 struct ecryptfs_cipher_code_str_map_elem {
        char cipher_str[16];
-       u16 cipher_code;
+       u8 cipher_code;
 };
 
 /* Add support for additional ciphers by adding elements here. The
@@ -1152,10 +1152,10 @@ ecryptfs_cipher_code_str_map[] = {
  *
  * Returns zero on no match, or the cipher code on match
  */
-u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
+u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
 {
        int i;
-       u16 code = 0;
+       u8 code = 0;
        struct ecryptfs_cipher_code_str_map_elem *map =
                ecryptfs_cipher_code_str_map;
 
@@ -1187,7 +1187,7 @@ u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
  *
  * Returns zero on success
  */
-int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
+int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code)
 {
        int rc = 0;
        int i;
@@ -1236,7 +1236,8 @@ ecryptfs_write_header_metadata(char *virt,
 
        header_extent_size = (u32)crypt_stat->extent_size;
        num_header_extents_at_front =
-               (u16)crypt_stat->num_header_extents_at_front;
+               (u16)(crypt_stat->num_header_bytes_at_front
+                     / crypt_stat->extent_size);
        header_extent_size = cpu_to_be32(header_extent_size);
        memcpy(virt, &header_extent_size, 4);
        virt += 4;
@@ -1311,40 +1312,16 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size,
 static int
 ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
                                    struct dentry *ecryptfs_dentry,
-                                   char *page_virt)
+                                   char *virt)
 {
-       int current_header_page;
-       int header_pages;
        int rc;
 
-       rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt,
-                                 0, PAGE_CACHE_SIZE);
-       if (rc) {
+       rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
+                                 0, crypt_stat->num_header_bytes_at_front);
+       if (rc)
                printk(KERN_ERR "%s: Error attempting to write header "
                       "information to lower file; rc = [%d]\n", __FUNCTION__,
                       rc);
-               goto out;
-       }
-       header_pages = ((crypt_stat->extent_size
-                        * crypt_stat->num_header_extents_at_front)
-                       / PAGE_CACHE_SIZE);
-       memset(page_virt, 0, PAGE_CACHE_SIZE);
-       current_header_page = 1;
-       while (current_header_page < header_pages) {
-               loff_t offset;
-
-               offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT);
-               if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode,
-                                              page_virt, offset,
-                                              PAGE_CACHE_SIZE))) {
-                       printk(KERN_ERR "%s: Error attempting to write header "
-                              "information to lower file; rc = [%d]\n",
-                              __FUNCTION__, rc);
-                       goto out;
-               }
-               current_header_page++;
-       }
-out:
        return rc;
 }
 
@@ -1370,15 +1347,13 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
  * retrieved via a prompt.  Exactly what happens at this point should
  * be policy-dependent.
  *
- * TODO: Support header information spanning multiple pages
- *
  * Returns zero on success; non-zero on error
  */
 int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
 {
        struct ecryptfs_crypt_stat *crypt_stat =
                &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
-       char *page_virt;
+       char *virt;
        size_t size = 0;
        int rc = 0;
 
@@ -1389,40 +1364,39 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
                        goto out;
                }
        } else {
+               printk(KERN_WARNING "%s: Encrypted flag not set\n",
+                      __FUNCTION__);
                rc = -EINVAL;
-               ecryptfs_printk(KERN_WARNING,
-                               "Called with crypt_stat->encrypted == 0\n");
                goto out;
        }
        /* Released in this function */
-       page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER);
-       if (!page_virt) {
-               ecryptfs_printk(KERN_ERR, "Out of memory\n");
+       virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
+       if (!virt) {
+               printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__);
                rc = -ENOMEM;
                goto out;
        }
-       rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat,
-                                        ecryptfs_dentry);
+       rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat,
+                                        ecryptfs_dentry);
        if (unlikely(rc)) {
-               ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
-               memset(page_virt, 0, PAGE_CACHE_SIZE);
+               printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
+                      __FUNCTION__, rc);
                goto out_free;
        }
        if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
                rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry,
-                                                     crypt_stat, page_virt,
-                                                     size);
+                                                     crypt_stat, virt, size);
        else
                rc = ecryptfs_write_metadata_to_contents(crypt_stat,
-                                                        ecryptfs_dentry,
-                                                        page_virt);
+                                                        ecryptfs_dentry, virt);
        if (rc) {
-               printk(KERN_ERR "Error writing metadata out to lower file; "
-                      "rc = [%d]\n", rc);
+               printk(KERN_ERR "%s: Error writing metadata out to lower file; "
+                      "rc = [%d]\n", __FUNCTION__, rc);
                goto out_free;
        }
 out_free:
-       kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+       memset(virt, 0, crypt_stat->num_header_bytes_at_front);
+       kfree(virt);
 out:
        return rc;
 }
@@ -1442,16 +1416,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
        virt += sizeof(u32);
        memcpy(&num_header_extents_at_front, virt, sizeof(u16));
        num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
-       crypt_stat->num_header_extents_at_front =
-               (int)num_header_extents_at_front;
+       crypt_stat->num_header_bytes_at_front =
+               (((size_t)num_header_extents_at_front
+                 * (size_t)header_extent_size));
        (*bytes_read) = (sizeof(u32) + sizeof(u16));
        if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
-           && ((crypt_stat->extent_size
-                * crypt_stat->num_header_extents_at_front)
+           && (crypt_stat->num_header_bytes_at_front
                < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
                rc = -EINVAL;
-               printk(KERN_WARNING "Invalid number of header extents: [%zd]\n",
-                      crypt_stat->num_header_extents_at_front);
+               printk(KERN_WARNING "Invalid header size: [%zd]\n",
+                      crypt_stat->num_header_bytes_at_front);
        }
        return rc;
 }
@@ -1466,7 +1440,8 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
  */
 static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
 {
-       crypt_stat->num_header_extents_at_front = 2;
+       crypt_stat->num_header_bytes_at_front =
+               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
 }
 
 /**
@@ -1552,9 +1527,10 @@ int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode)
        size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,
                                       page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);
        if (size < 0) {
-               printk(KERN_ERR "Error attempting to read the [%s] "
-                      "xattr from the lower file; return value = [%zd]\n",
-                      ECRYPTFS_XATTR_NAME, size);
+               if (unlikely(ecryptfs_verbosity > 0))
+                       printk(KERN_INFO "Error attempting to read the [%s] "
+                              "xattr from the lower file; return value = "
+                              "[%zd]\n", ECRYPTFS_XATTR_NAME, size);
                rc = -EINVAL;
                goto out;
        }
@@ -1802,7 +1778,7 @@ out:
 }
 
 struct kmem_cache *ecryptfs_key_tfm_cache;
-struct list_head key_tfm_list;
+static struct list_head key_tfm_list;
 struct mutex key_tfm_list_mutex;
 
 int ecryptfs_init_crypto(void)
@@ -1812,6 +1788,11 @@ int ecryptfs_init_crypto(void)
        return 0;
 }
 
+/**
+ * ecryptfs_destroy_crypto - free all cached key_tfms on key_tfm_list
+ *
+ * Called only at module unload time
+ */
 int ecryptfs_destroy_crypto(void)
 {
        struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp;
@@ -1835,6 +1816,8 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
        struct ecryptfs_key_tfm *tmp_tfm;
        int rc = 0;
 
+       BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
+
        tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL);
        if (key_tfm != NULL)
                (*key_tfm) = tmp_tfm;
@@ -1861,13 +1844,50 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
                        (*key_tfm) = NULL;
                goto out;
        }
-       mutex_lock(&key_tfm_list_mutex);
        list_add(&tmp_tfm->key_tfm_list, &key_tfm_list);
-       mutex_unlock(&key_tfm_list_mutex);
 out:
        return rc;
 }
 
+/**
+ * ecryptfs_tfm_exists - Search for existing tfm for cipher_name.
+ * @cipher_name: the name of the cipher to search for
+ * @key_tfm: set to corresponding tfm if found
+ *
+ * Searches for cached key_tfm matching @cipher_name
+ * Must be called with &key_tfm_list_mutex held
+ * Returns 1 if found, with @key_tfm set
+ * Returns 0 if not found, with @key_tfm set to NULL
+ */
+int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm)
+{
+       struct ecryptfs_key_tfm *tmp_key_tfm;
+
+       BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
+
+       list_for_each_entry(tmp_key_tfm, &key_tfm_list, key_tfm_list) {
+               if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) {
+                       if (key_tfm)
+                               (*key_tfm) = tmp_key_tfm;
+                       return 1;
+               }
+       }
+       if (key_tfm)
+               (*key_tfm) = NULL;
+       return 0;
+}
+
+/**
+ * ecryptfs_get_tfm_and_mutex_for_cipher_name
+ *
+ * @tfm: set to cached tfm found, or new tfm created
+ * @tfm_mutex: set to mutex for cached tfm found, or new tfm created
+ * @cipher_name: the name of the cipher to search for and/or add
+ *
+ * Sets pointers to @tfm & @tfm_mutex matching @cipher_name.
+ * Searches for cached item first, and creates new if not found.
+ * Returns 0 on success, non-zero if adding new cipher failed
+ */
 int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
                                               struct mutex **tfm_mutex,
                                               char *cipher_name)
@@ -1877,22 +1897,17 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
 
        (*tfm) = NULL;
        (*tfm_mutex) = NULL;
+
        mutex_lock(&key_tfm_list_mutex);
-       list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) {
-               if (strcmp(key_tfm->cipher_name, cipher_name) == 0) {
-                       (*tfm) = key_tfm->key_tfm;
-                       (*tfm_mutex) = &key_tfm->key_tfm_mutex;
-                       mutex_unlock(&key_tfm_list_mutex);
+       if (!ecryptfs_tfm_exists(cipher_name, &key_tfm)) {
+               rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);
+               if (rc) {
+                       printk(KERN_ERR "Error adding new key_tfm to list; "
+                                       "rc = [%d]\n", rc);
                        goto out;
                }
        }
        mutex_unlock(&key_tfm_list_mutex);
-       rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);
-       if (rc) {
-               printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n",
-                      rc);
-               goto out;
-       }
        (*tfm) = key_tfm->key_tfm;
        (*tfm_mutex) = &key_tfm->key_tfm_mutex;
 out:
index ce7a5d4..5007f78 100644 (file)
@@ -234,10 +234,11 @@ struct ecryptfs_crypt_stat {
 #define ECRYPTFS_KEY_VALID          0x00000080
 #define ECRYPTFS_METADATA_IN_XATTR  0x00000100
 #define ECRYPTFS_VIEW_AS_ENCRYPTED  0x00000200
+#define ECRYPTFS_KEY_SET            0x00000400
        u32 flags;
        unsigned int file_version;
        size_t iv_bytes;
-       size_t num_header_extents_at_front;
+       size_t num_header_bytes_at_front;
        size_t extent_size; /* Data extent size; default is 4096 */
        size_t key_size;
        size_t extent_shift;
@@ -322,7 +323,6 @@ struct ecryptfs_key_tfm {
        unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
 };
 
-extern struct list_head key_tfm_list;
 extern struct mutex key_tfm_list_mutex;
 
 /**
@@ -521,11 +521,9 @@ extern struct kmem_cache *ecryptfs_file_info_cache;
 extern struct kmem_cache *ecryptfs_dentry_info_cache;
 extern struct kmem_cache *ecryptfs_inode_info_cache;
 extern struct kmem_cache *ecryptfs_sb_info_cache;
-extern struct kmem_cache *ecryptfs_header_cache_0;
 extern struct kmem_cache *ecryptfs_header_cache_1;
 extern struct kmem_cache *ecryptfs_header_cache_2;
 extern struct kmem_cache *ecryptfs_xattr_cache;
-extern struct kmem_cache *ecryptfs_lower_page_cache;
 extern struct kmem_cache *ecryptfs_key_record_cache;
 extern struct kmem_cache *ecryptfs_key_sig_cache;
 extern struct kmem_cache *ecryptfs_global_auth_tok_cache;
@@ -562,8 +560,8 @@ int ecryptfs_read_and_validate_header_region(char *data,
                                             struct inode *ecryptfs_inode);
 int ecryptfs_read_and_validate_xattr_region(char *page_virt,
                                            struct dentry *ecryptfs_dentry);
-u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
-int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
+u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code);
 void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
 int ecryptfs_generate_key_packet_set(char *dest_base,
                                     struct ecryptfs_crypt_stat *crypt_stat,
@@ -576,8 +574,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
 int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
 int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
 void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
-ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
-                         size_t size);
 ssize_t
 ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,
                        void *value, size_t size);
@@ -623,6 +619,7 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
                         size_t key_size);
 int ecryptfs_init_crypto(void);
 int ecryptfs_destroy_crypto(void);
+int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm);
 int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,
                                               struct mutex **tfm_mutex,
                                               char *cipher_name);
@@ -631,8 +628,6 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
                                      char *sig);
 int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start,
                         int num_zeros);
-void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
-                                     struct ecryptfs_crypt_stat *crypt_stat);
 int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
                         loff_t offset, size_t size);
 int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
@@ -646,8 +641,6 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
                                     pgoff_t page_index,
                                     size_t offset_in_page, size_t size,
                                     struct inode *ecryptfs_inode);
-int ecryptfs_read(char *data, loff_t offset, size_t size,
-                 struct file *ecryptfs_file);
 struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
 
 #endif /* #ifndef ECRYPTFS_KERNEL_H */
index c98c469..2b8f5ed 100644 (file)
@@ -209,9 +209,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
                        if (!(mount_crypt_stat->flags
                              & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
                                rc = -EIO;
-                               printk(KERN_WARNING "Attempt to read file that "
+                               printk(KERN_WARNING "Either the lower file "
                                       "is not in a valid eCryptfs format, "
-                                      "and plaintext passthrough mode is not "
+                                      "or the key could not be retrieved. "
+                                      "Plaintext passthrough mode is not "
                                       "enabled; returning -EIO\n");
                                mutex_unlock(&crypt_stat->cs_mutex);
                                goto out_free;
index 5a71918..edd1e44 100644 (file)
@@ -365,8 +365,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
                dentry->d_sb)->mount_crypt_stat;
        if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
                if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
-                       file_size = ((crypt_stat->extent_size
-                                     * crypt_stat->num_header_extents_at_front)
+                       file_size = (crypt_stat->num_header_bytes_at_front
                                     + i_size_read(lower_dentry->d_inode));
                else
                        file_size = i_size_read(lower_dentry->d_inode);
@@ -685,7 +684,7 @@ ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
  * @crypt_stat: Crypt_stat associated with file
  * @upper_size: Size of the upper file
  *
- * Calculate the requried size of the lower file based on the
+ * Calculate the required size of the lower file based on the
  * specified size of the upper file. This calculation is based on the
  * number of headers in the underlying file and the extent size.
  *
@@ -697,8 +696,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
 {
        loff_t lower_size;
 
-       lower_size = (crypt_stat->extent_size
-                     * crypt_stat->num_header_extents_at_front);
+       lower_size = crypt_stat->num_header_bytes_at_front;
        if (upper_size != 0) {
                loff_t num_extents;
 
@@ -875,11 +873,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
                        if (!(mount_crypt_stat->flags
                              & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
                                rc = -EIO;
-                               printk(KERN_WARNING "Attempt to read file that "
+                               printk(KERN_WARNING "Either the lower file "
                                       "is not in a valid eCryptfs format, "
-                                      "and plaintext passthrough mode is not "
+                                      "or the key could not be retrieved. "
+                                      "Plaintext passthrough mode is not "
                                       "enabled; returning -EIO\n");
-
                                mutex_unlock(&crypt_stat->cs_mutex);
                                goto out;
                        }
@@ -954,7 +952,7 @@ out:
        return rc;
 }
 
-ssize_t
+static ssize_t
 ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
                  size_t size)
 {
index f458c1f..682b1b2 100644 (file)
@@ -189,7 +189,7 @@ out:
 }
 
 static int
-parse_tag_65_packet(struct ecryptfs_session_key *session_key, u16 *cipher_code,
+parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
                    struct ecryptfs_message *msg)
 {
        size_t i = 0;
@@ -275,7 +275,7 @@ out:
 
 
 static int
-write_tag_66_packet(char *signature, size_t cipher_code,
+write_tag_66_packet(char *signature, u8 cipher_code,
                    struct ecryptfs_crypt_stat *crypt_stat, char **packet,
                    size_t *packet_len)
 {
@@ -428,7 +428,7 @@ static int
 decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                                  struct ecryptfs_crypt_stat *crypt_stat)
 {
-       u16 cipher_code = 0;
+       u8 cipher_code = 0;
        struct ecryptfs_msg_ctx *msg_ctx;
        struct ecryptfs_message *msg = NULL;
        char *auth_tok_sig;
@@ -1537,7 +1537,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
        struct scatterlist dst_sg;
        struct scatterlist src_sg;
        struct mutex *tfm_mutex = NULL;
-       size_t cipher_code;
+       u8 cipher_code;
        size_t packet_size_length;
        size_t max_packet_size;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
index 0249aa4..778c420 100644 (file)
@@ -117,7 +117,7 @@ void __ecryptfs_printk(const char *fmt, ...)
  *
  * Returns zero on success; non-zero otherwise
  */
-int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
+static int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
 {
        struct ecryptfs_inode_info *inode_info =
                ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
@@ -226,17 +226,15 @@ out:
        return rc;
 }
 
-enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
-       ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
-       ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
+enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
+       ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher,
+       ecryptfs_opt_ecryptfs_key_bytes,
        ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,
        ecryptfs_opt_encrypted_view, ecryptfs_opt_err };
 
 static match_table_t tokens = {
        {ecryptfs_opt_sig, "sig=%s"},
        {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
-       {ecryptfs_opt_debug, "debug=%u"},
-       {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
        {ecryptfs_opt_cipher, "cipher=%s"},
        {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
        {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
@@ -313,7 +311,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
        substring_t args[MAX_OPT_ARGS];
        int token;
        char *sig_src;
-       char *debug_src;
        char *cipher_name_dst;
        char *cipher_name_src;
        char *cipher_key_bytes_src;
@@ -341,16 +338,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
                        }
                        sig_set = 1;
                        break;
-               case ecryptfs_opt_debug:
-               case ecryptfs_opt_ecryptfs_debug:
-                       debug_src = args[0].from;
-                       ecryptfs_verbosity =
-                               (int)simple_strtol(debug_src, &debug_src,
-                                                  0);
-                       ecryptfs_printk(KERN_DEBUG,
-                                       "Verbosity set to [%d]" "\n",
-                                       ecryptfs_verbosity);
-                       break;
                case ecryptfs_opt_cipher:
                case ecryptfs_opt_ecryptfs_cipher:
                        cipher_name_src = args[0].from;
@@ -423,9 +410,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
        if (!cipher_key_bytes_set) {
                mount_crypt_stat->global_default_cipher_key_size = 0;
        }
-       rc = ecryptfs_add_new_key_tfm(
-               NULL, mount_crypt_stat->global_default_cipher_name,
-               mount_crypt_stat->global_default_cipher_key_size);
+       mutex_lock(&key_tfm_list_mutex);
+       if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,
+                                NULL))
+               rc = ecryptfs_add_new_key_tfm(
+                       NULL, mount_crypt_stat->global_default_cipher_name,
+                       mount_crypt_stat->global_default_cipher_key_size);
+       mutex_unlock(&key_tfm_list_mutex);
        if (rc) {
                printk(KERN_ERR "Error attempting to initialize cipher with "
                       "name = [%s] and key size = [%td]; rc = [%d]\n",
@@ -653,11 +644,6 @@ static struct ecryptfs_cache_info {
                .name = "ecryptfs_sb_cache",
                .size = sizeof(struct ecryptfs_sb_info),
        },
-       {
-               .cache = &ecryptfs_header_cache_0,
-               .name = "ecryptfs_headers_0",
-               .size = PAGE_CACHE_SIZE,
-       },
        {
                .cache = &ecryptfs_header_cache_1,
                .name = "ecryptfs_headers_1",
@@ -821,6 +807,10 @@ static int __init ecryptfs_init(void)
                       "rc = [%d]\n", rc);
                goto out_release_messaging;
        }
+       if (ecryptfs_verbosity > 0)
+               printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values "
+                       "will be written to the syslog!\n", ecryptfs_verbosity);
+
        goto out;
 out_release_messaging:
        ecryptfs_release_messaging(ecryptfs_transport);
index 0535412..dc74b18 100644 (file)
@@ -34,8 +34,6 @@
 #include <linux/scatterlist.h>
 #include "ecryptfs_kernel.h"
 
-struct kmem_cache *ecryptfs_lower_page_cache;
-
 /**
  * ecryptfs_get_locked_page
  *
@@ -102,13 +100,14 @@ static void set_header_info(char *page_virt,
                            struct ecryptfs_crypt_stat *crypt_stat)
 {
        size_t written;
-       int save_num_header_extents_at_front =
-               crypt_stat->num_header_extents_at_front;
+       size_t save_num_header_bytes_at_front =
+               crypt_stat->num_header_bytes_at_front;
 
-       crypt_stat->num_header_extents_at_front = 1;
+       crypt_stat->num_header_bytes_at_front =
+               ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
        ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
-       crypt_stat->num_header_extents_at_front =
-               save_num_header_extents_at_front;
+       crypt_stat->num_header_bytes_at_front =
+               save_num_header_bytes_at_front;
 }
 
 /**
@@ -134,8 +133,11 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
                loff_t view_extent_num = ((((loff_t)page->index)
                                           * num_extents_per_page)
                                          + extent_num_in_page);
+               size_t num_header_extents_at_front =
+                       (crypt_stat->num_header_bytes_at_front
+                        / crypt_stat->extent_size);
 
-               if (view_extent_num < crypt_stat->num_header_extents_at_front) {
+               if (view_extent_num < num_header_extents_at_front) {
                        /* This is a header extent */
                        char *page_virt;
 
@@ -157,9 +159,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
                } else {
                        /* This is an encrypted data extent */
                        loff_t lower_offset =
-                               ((view_extent_num -
-                                 crypt_stat->num_header_extents_at_front)
-                                * crypt_stat->extent_size);
+                               ((view_extent_num * crypt_stat->extent_size)
+                                - crypt_stat->num_header_bytes_at_front);
 
                        rc = ecryptfs_read_lower_page_segment(
                                page, (lower_offset >> PAGE_CACHE_SHIFT),
index 948f576..0c49286 100644 (file)
@@ -293,6 +293,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
        return rc;
 }
 
+#if 0
 /**
  * ecryptfs_read
  * @data: The virtual address into which to write the data read (and
@@ -371,3 +372,4 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
 out:
        return rc;
 }
+#endif  /*  0  */
index 4859c4e..c27ac2b 100644 (file)
@@ -156,32 +156,38 @@ static void ecryptfs_clear_inode(struct inode *inode)
 /**
  * ecryptfs_show_options
  *
- * Prints the directory we are currently mounted over.
- * Returns zero on success; non-zero otherwise
+ * Prints the mount options for a given superblock.
+ * Returns zero; does not fail.
  */
 static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
 {
        struct super_block *sb = mnt->mnt_sb;
-       struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
-       struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
-       char *tmp_page;
-       char *path;
-       int rc = 0;
-
-       tmp_page = (char *)__get_free_page(GFP_KERNEL);
-       if (!tmp_page) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
-       if (IS_ERR(path)) {
-               rc = PTR_ERR(path);
-               goto out;
+       struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+               &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
+       struct ecryptfs_global_auth_tok *walker;
+
+       mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
+       list_for_each_entry(walker,
+                           &mount_crypt_stat->global_auth_tok_list,
+                           mount_crypt_stat_list) {
+               seq_printf(m, ",ecryptfs_sig=%s", walker->sig);
        }
-       seq_printf(m, ",dir=%s", path);
-       free_page((unsigned long)tmp_page);
-out:
-       return rc;
+       mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
+
+       seq_printf(m, ",ecryptfs_cipher=%s",
+               mount_crypt_stat->global_default_cipher_name);
+
+       if (mount_crypt_stat->global_default_cipher_key_size)
+               seq_printf(m, ",ecryptfs_key_bytes=%zd",
+                          mount_crypt_stat->global_default_cipher_key_size);
+       if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)
+               seq_printf(m, ",ecryptfs_passthrough");
+       if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED)
+               seq_printf(m, ",ecryptfs_xattr_metadata");
+       if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED)
+               seq_printf(m, ",ecryptfs_encrypted_view");
+
+       return 0;
 }
 
 const struct super_operations ecryptfs_sops = {
index 2ce19c0..a9f130c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/anon_inodes.h>
 #include <linux/eventfd.h>
+#include <linux/syscalls.h>
 
 struct eventfd_ctx {
        wait_queue_head_t wqh;
index 377ad17..e7b2baf 100644 (file)
@@ -69,9 +69,53 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
        return desc + offset;
 }
 
+static int ext2_valid_block_bitmap(struct super_block *sb,
+                                       struct ext2_group_desc *desc,
+                                       unsigned int block_group,
+                                       struct buffer_head *bh)
+{
+       ext2_grpblk_t offset;
+       ext2_grpblk_t next_zero_bit;
+       ext2_fsblk_t bitmap_blk;
+       ext2_fsblk_t group_first_block;
+
+       group_first_block = ext2_group_first_block_no(sb, block_group);
+
+       /* check whether block bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext2_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext2_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode table block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_table);
+       offset = bitmap_blk - group_first_block;
+       next_zero_bit = ext2_find_next_zero_bit(bh->b_data,
+                               offset + EXT2_SB(sb)->s_itb_per_group,
+                               offset);
+       if (next_zero_bit >= offset + EXT2_SB(sb)->s_itb_per_group)
+               /* good bitmap for inode tables */
+               return 1;
+
+err_out:
+       ext2_error(sb, __FUNCTION__,
+                       "Invalid block bitmap - "
+                       "block_group = %d, block = %lu",
+                       block_group, bitmap_blk);
+       return 0;
+}
+
 /*
- * Read the bitmap for a given block_group, reading into the specified 
- * slot in the superblock's bitmap cache.
+ * Read the bitmap for a given block_group,and validate the
+ * bits for block/inode/inode tables are set in the bitmaps
  *
  * Return buffer_head on success or NULL in case of failure.
  */
@@ -80,17 +124,36 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
 {
        struct ext2_group_desc * desc;
        struct buffer_head * bh = NULL;
-       
-       desc = ext2_get_group_desc (sb, block_group, NULL);
+       ext2_fsblk_t bitmap_blk;
+
+       desc = ext2_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               goto error_out;
-       bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-       if (!bh)
-               ext2_error (sb, "read_block_bitmap",
+               return NULL;
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       bh = sb_getblk(sb, bitmap_blk);
+       if (unlikely(!bh)) {
+               ext2_error(sb, __FUNCTION__,
+                           "Cannot read block bitmap - "
+                           "block_group = %d, block_bitmap = %u",
+                           block_group, le32_to_cpu(desc->bg_block_bitmap));
+               return NULL;
+       }
+       if (likely(bh_uptodate_or_lock(bh)))
+               return bh;
+
+       if (bh_submit_read(bh) < 0) {
+               brelse(bh);
+               ext2_error(sb, __FUNCTION__,
                            "Cannot read block bitmap - "
                            "block_group = %d, block_bitmap = %u",
                            block_group, le32_to_cpu(desc->bg_block_bitmap));
-error_out:
+               return NULL;
+       }
+       if (!ext2_valid_block_bitmap(sb, desc, block_group, bh)) {
+               brelse(bh);
+               return NULL;
+       }
+
        return bh;
 }
 
@@ -474,11 +537,13 @@ do_more:
            in_range (block, le32_to_cpu(desc->bg_inode_table),
                      sbi->s_itb_per_group) ||
            in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),
-                     sbi->s_itb_per_group))
+                     sbi->s_itb_per_group)) {
                ext2_error (sb, "ext2_free_blocks",
                            "Freeing blocks in system zones - "
                            "Block = %lu, count = %lu",
                            block, count);
+               goto error_return;
+       }
 
        for (i = 0, group_freed = 0; i < count; i++) {
                if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
@@ -1250,8 +1315,8 @@ retry_alloc:
        smp_rmb();
 
        /*
-        * Now search the rest of the groups.  We assume that 
-        * i and gdp correctly point to the last group visited.
+        * Now search the rest of the groups.  We assume that
+        * group_no and gdp correctly point to the last group visited.
         */
        for (bgi = 0; bgi < ngroups; bgi++) {
                group_no++;
@@ -1311,11 +1376,13 @@ allocated:
            in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
                      EXT2_SB(sb)->s_itb_per_group) ||
            in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
-                     EXT2_SB(sb)->s_itb_per_group))
+                     EXT2_SB(sb)->s_itb_per_group)) {
                ext2_error(sb, "ext2_new_blocks",
                            "Allocating block in system zone - "
                            "blocks from "E2FSBLK", length %lu",
                            ret_block, num);
+               goto out;
+       }
 
        performed_allocation = 1;
 
@@ -1466,9 +1533,6 @@ int ext2_bg_has_super(struct super_block *sb, int group)
  */
 unsigned long ext2_bg_num_gdb(struct super_block *sb, int group)
 {
-       if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&&
-           !ext2_group_sparse(group))
-               return 0;
-       return EXT2_SB(sb)->s_gdb_count;
+       return ext2_bg_has_super(sb, group) ? EXT2_SB(sb)->s_gdb_count : 0;
 }
 
index d868e26..8dededd 100644 (file)
@@ -703,7 +703,7 @@ const struct file_operations ext2_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ext2_readdir,
-       .ioctl          = ext2_ioctl,
+       .unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext2_compat_ioctl,
 #endif
index c87ae29..bb9948c 100644 (file)
@@ -139,8 +139,7 @@ int __ext2_write_begin(struct file *file, struct address_space *mapping,
                struct page **pagep, void **fsdata);
 
 /* ioctl.c */
-extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
-                      unsigned long);
+extern long ext2_ioctl(struct file *, unsigned int, unsigned long);
 extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long);
 
 /* namei.c */
index c051798..5f2fa9c 100644 (file)
@@ -48,7 +48,7 @@ const struct file_operations ext2_file_operations = {
        .write          = do_sync_write,
        .aio_read       = generic_file_aio_read,
        .aio_write      = generic_file_aio_write,
-       .ioctl          = ext2_ioctl,
+       .unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext2_compat_ioctl,
 #endif
@@ -65,7 +65,7 @@ const struct file_operations ext2_xip_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = xip_file_read,
        .write          = xip_file_write,
-       .ioctl          = ext2_ioctl,
+       .unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ext2_compat_ioctl,
 #endif
index b1ab32a..03978ec 100644 (file)
@@ -286,15 +286,12 @@ static unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
  *     ext2_find_goal - find a prefered place for allocation.
  *     @inode: owner
  *     @block:  block we want
- *     @chain:  chain of indirect blocks
  *     @partial: pointer to the last triple within a chain
  *
  *     Returns preferred place for a block (the goal).
  */
 
-static inline int ext2_find_goal(struct inode *inode,
-                                long block,
-                                Indirect chain[4],
+static inline int ext2_find_goal(struct inode *inode, long block,
                                 Indirect *partial)
 {
        struct ext2_block_alloc_info *block_i;
@@ -569,7 +566,6 @@ static void ext2_splice_branch(struct inode *inode,
  *
  * `handle' can be NULL if create == 0.
  *
- * The BKL may not be held on entry here.  Be sure to take it early.
  * return > 0, # of blocks mapped or allocated.
  * return = 0, if plain lookup failed.
  * return < 0, error case.
@@ -639,7 +635,7 @@ reread:
        if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
                ext2_init_block_alloc_info(inode);
 
-       goal = ext2_find_goal(inode, iblock, chain, partial);
+       goal = ext2_find_goal(inode, iblock, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
        indirect_blks = (chain + depth) - partial - 1;
index 320b2cb..b8ea11f 100644 (file)
@@ -17,9 +17,9 @@
 #include <asm/uaccess.h>
 
 
-int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
-               unsigned long arg)
+long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = filp->f_dentry->d_inode;
        struct ext2_inode_info *ei = EXT2_I(inode);
        unsigned int flags;
        unsigned short rsv_window_size;
@@ -141,9 +141,6 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 #ifdef CONFIG_COMPAT
 long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
-       int ret;
-
        /* These are just misnamed, they actually get/put from/to user an int */
        switch (cmd) {
        case EXT2_IOC32_GETFLAGS:
@@ -161,9 +158,6 @@ long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        default:
                return -ENOIOCTLCMD;
        }
-       lock_kernel();
-       ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
-       unlock_kernel();
-       return ret;
+       return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
 }
 #endif
index 6abaf75..1ba18b7 100644 (file)
@@ -234,16 +234,16 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
            le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) {
                seq_printf(seq, ",resgid=%u", sbi->s_resgid);
        }
-       if (test_opt(sb, ERRORS_CONT)) {
+       if (test_opt(sb, ERRORS_RO)) {
                int def_errors = le16_to_cpu(es->s_errors);
 
                if (def_errors == EXT2_ERRORS_PANIC ||
-                   def_errors == EXT2_ERRORS_RO) {
-                       seq_puts(seq, ",errors=continue");
+                   def_errors == EXT2_ERRORS_CONTINUE) {
+                       seq_puts(seq, ",errors=remount-ro");
                }
        }
-       if (test_opt(sb, ERRORS_RO))
-               seq_puts(seq, ",errors=remount-ro");
+       if (test_opt(sb, ERRORS_CONT))
+               seq_puts(seq, ",errors=continue");
        if (test_opt(sb, ERRORS_PANIC))
                seq_puts(seq, ",errors=panic");
        if (test_opt(sb, NO_UID32))
@@ -617,27 +617,24 @@ static int ext2_setup_super (struct super_block * sb,
        return res;
 }
 
-static int ext2_check_descriptors (struct super_block * sb)
+static int ext2_check_descriptors(struct super_block *sb)
 {
        int i;
-       int desc_block = 0;
        struct ext2_sb_info *sbi = EXT2_SB(sb);
        unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        unsigned long last_block;
-       struct ext2_group_desc * gdp = NULL;
 
        ext2_debug ("Checking group descriptors");
 
-       for (i = 0; i < sbi->s_groups_count; i++)
-       {
+       for (i = 0; i < sbi->s_groups_count; i++) {
+               struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL);
+
                if (i == sbi->s_groups_count - 1)
                        last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
                else
                        last_block = first_block +
                                (EXT2_BLOCKS_PER_GROUP(sb) - 1);
 
-               if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
-                       gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data;
                if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
                    le32_to_cpu(gdp->bg_block_bitmap) > last_block)
                {
@@ -667,7 +664,6 @@ static int ext2_check_descriptors (struct super_block * sb)
                        return 0;
                }
                first_block += EXT2_BLOCKS_PER_GROUP(sb);
-               gdp++;
        }
        return 1;
 }
@@ -820,10 +816,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
        
        if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
-       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO)
-               set_opt(sbi->s_mount_opt, ERRORS_RO);
-       else
+       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
                set_opt(sbi->s_mount_opt, ERRORS_CONT);
+       else
+               set_opt(sbi->s_mount_opt, ERRORS_RO);
 
        sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -868,8 +864,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 
        blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
 
-       if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
-                                 (sb->s_blocksize != blocksize))) {
+       if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) {
                if (!silent)
                        printk("XIP: Unsupported blocksize\n");
                goto failed_mount;
index a8ba7e8..a757130 100644 (file)
@@ -80,13 +80,57 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
        return desc + offset;
 }
 
+static int ext3_valid_block_bitmap(struct super_block *sb,
+                                       struct ext3_group_desc *desc,
+                                       unsigned int block_group,
+                                       struct buffer_head *bh)
+{
+       ext3_grpblk_t offset;
+       ext3_grpblk_t next_zero_bit;
+       ext3_fsblk_t bitmap_blk;
+       ext3_fsblk_t group_first_block;
+
+       group_first_block = ext3_group_first_block_no(sb, block_group);
+
+       /* check whether block bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext3_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode bitmap block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap);
+       offset = bitmap_blk - group_first_block;
+       if (!ext3_test_bit(offset, bh->b_data))
+               /* bad block bitmap */
+               goto err_out;
+
+       /* check whether the inode table block number is set */
+       bitmap_blk = le32_to_cpu(desc->bg_inode_table);
+       offset = bitmap_blk - group_first_block;
+       next_zero_bit = ext3_find_next_zero_bit(bh->b_data,
+                               offset + EXT3_SB(sb)->s_itb_per_group,
+                               offset);
+       if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group)
+               /* good bitmap for inode tables */
+               return 1;
+
+err_out:
+       ext3_error(sb, __FUNCTION__,
+                       "Invalid block bitmap - "
+                       "block_group = %d, block = %lu",
+                       block_group, bitmap_blk);
+       return 0;
+}
+
 /**
  * read_block_bitmap()
  * @sb:                        super block
  * @block_group:       given block group
  *
- * Read the bitmap for a given block_group, reading into the specified
- * slot in the superblock's bitmap cache.
+ * Read the bitmap for a given block_group,and validate the
+ * bits for block/inode/inode tables are set in the bitmaps
  *
  * Return buffer_head on success or NULL in case of failure.
  */
@@ -95,17 +139,35 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
 {
        struct ext3_group_desc * desc;
        struct buffer_head * bh = NULL;
+       ext3_fsblk_t bitmap_blk;
 
-       desc = ext3_get_group_desc (sb, block_group, NULL);
+       desc = ext3_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               goto error_out;
-       bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-       if (!bh)
-               ext3_error (sb, "read_block_bitmap",
+               return NULL;
+       bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+       bh = sb_getblk(sb, bitmap_blk);
+       if (unlikely(!bh)) {
+               ext3_error(sb, __FUNCTION__,
                            "Cannot read block bitmap - "
                            "block_group = %d, block_bitmap = %u",
                            block_group, le32_to_cpu(desc->bg_block_bitmap));
-error_out:
+               return NULL;
+       }
+       if (likely(bh_uptodate_or_lock(bh)))
+               return bh;
+
+       if (bh_submit_read(bh) < 0) {
+               brelse(bh);
+               ext3_error(sb, __FUNCTION__,
+                           "Cannot read block bitmap - "
+                           "block_group = %d, block_bitmap = %u",
+                           block_group, le32_to_cpu(desc->bg_block_bitmap));
+               return NULL;
+       }
+       if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) {
+               brelse(bh);
+               return NULL;
+       }
        return bh;
 }
 /*
@@ -468,11 +530,13 @@ do_more:
            in_range (block, le32_to_cpu(desc->bg_inode_table),
                      sbi->s_itb_per_group) ||
            in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),
-                     sbi->s_itb_per_group))
+                     sbi->s_itb_per_group)) {
                ext3_error (sb, "ext3_free_blocks",
                            "Freeing blocks in system zones - "
                            "Block = "E3FSBLK", count = %lu",
                            block, count);
+               goto error_return;
+       }
 
        /*
         * We are about to start releasing blocks in the bitmap,
@@ -1508,7 +1572,7 @@ retry_alloc:
 
        /*
         * Now search the rest of the groups.  We assume that
-        * i and gdp correctly point to the last group visited.
+        * group_no and gdp correctly point to the last group visited.
         */
        for (bgi = 0; bgi < ngroups; bgi++) {
                group_no++;
@@ -1575,11 +1639,13 @@ allocated:
            in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),
                      EXT3_SB(sb)->s_itb_per_group) ||
            in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),
-                     EXT3_SB(sb)->s_itb_per_group))
+                     EXT3_SB(sb)->s_itb_per_group)) {
                ext3_error(sb, "ext3_new_block",
                            "Allocating block in system zone - "
                            "blocks from "E3FSBLK", length %lu",
                             ret_block, num);
+               goto out;
+       }
 
        performed_allocation = 1;
 
@@ -1782,11 +1848,7 @@ static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group)
 
 static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group)
 {
-       if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
-                       !ext3_group_sparse(group))
-               return 0;
-       return EXT3_SB(sb)->s_gdb_count;
+       return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0;
 }
 
 /**
index 0775354..8a9ce2d 100644 (file)
@@ -439,16 +439,14 @@ static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind)
  *     ext3_find_goal - find a prefered place for allocation.
  *     @inode: owner
  *     @block:  block we want
- *     @chain:  chain of indirect blocks
  *     @partial: pointer to the last triple within a chain
- *     @goal:  place to store the result.
  *
  *     Normally this function find the prefered place for block allocation,
- *     stores it in *@goal and returns zero.
+ *     returns it.
  */
 
 static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
-               Indirect chain[4], Indirect *partial)
+                                  Indirect *partial)
 {
        struct ext3_block_alloc_info *block_i;
 
@@ -884,7 +882,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
        if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
                ext3_init_block_alloc_info(inode);
 
-       goal = ext3_find_goal(inode, iblock, chain, partial);
+       goal = ext3_find_goal(inode, iblock, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
        indirect_blks = (chain + depth) - partial - 1;
@@ -941,55 +939,45 @@ out:
        return err;
 }
 
-#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32)
+/* Maximum number of blocks we map for direct IO at once. */
+#define DIO_MAX_BLOCKS 4096
+/*
+ * Number of credits we need for writing DIO_MAX_BLOCKS:
+ * We need sb + group descriptor + bitmap + inode -> 4
+ * For B blocks with A block pointers per block we need:
+ * 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect).
+ * If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25.
+ */
+#define DIO_CREDITS 25
 
 static int ext3_get_block(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create)
 {
        handle_t *handle = ext3_journal_current_handle();
-       int ret = 0;
+       int ret = 0, started = 0;
        unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
 
-       if (!create)
-               goto get_block;         /* A read */
-
-       if (max_blocks == 1)
-               goto get_block;         /* A single block get */
-
-       if (handle->h_transaction->t_state == T_LOCKED) {
-               /*
-                * Huge direct-io writes can hold off commits for long
-                * periods of time.  Let this commit run.
-                */
-               ext3_journal_stop(handle);
-               handle = ext3_journal_start(inode, DIO_CREDITS);
-               if (IS_ERR(handle))
+       if (create && !handle) {        /* Direct IO write... */
+               if (max_blocks > DIO_MAX_BLOCKS)
+                       max_blocks = DIO_MAX_BLOCKS;
+               handle = ext3_journal_start(inode, DIO_CREDITS +
+                               2 * EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb));
+               if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
-               goto get_block;
-       }
-
-       if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
-               /*
-                * Getting low on buffer credits...
-                */
-               ret = ext3_journal_extend(handle, DIO_CREDITS);
-               if (ret > 0) {
-                       /*
-                        * Couldn't extend the transaction.  Start a new one.
-                        */
-                       ret = ext3_journal_restart(handle, DIO_CREDITS);
+                       goto out;
                }
+               started = 1;
        }
 
-get_block:
-       if (ret == 0) {
-               ret = ext3_get_blocks_handle(handle, inode, iblock,
+       ret = ext3_get_blocks_handle(handle, inode, iblock,
                                        max_blocks, bh_result, create, 0);
-               if (ret > 0) {
-                       bh_result->b_size = (ret << inode->i_blkbits);
-                       ret = 0;
-               }
+       if (ret > 0) {
+               bh_result->b_size = (ret << inode->i_blkbits);
+               ret = 0;
        }
+       if (started)
+               ext3_journal_stop(handle);
+out:
        return ret;
 }
 
@@ -1680,7 +1668,8 @@ static int ext3_releasepage(struct page *page, gfp_t wait)
  * if the machine crashes during the write.
  *
  * If the O_DIRECT write is intantiating holes inside i_size and the machine
- * crashes then stale disk data _may_ be exposed inside the file.
+ * crashes then stale disk data _may_ be exposed inside the file. But current
+ * VFS code falls back into buffered path in that case so we are safe.
  */
 static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
                        const struct iovec *iov, loff_t offset,
@@ -1689,7 +1678,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
        struct ext3_inode_info *ei = EXT3_I(inode);
-       handle_t *handle = NULL;
+       handle_t *handle;
        ssize_t ret;
        int orphan = 0;
        size_t count = iov_length(iov, nr_segs);
@@ -1697,17 +1686,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
        if (rw == WRITE) {
                loff_t final_size = offset + count;
 
-               handle = ext3_journal_start(inode, DIO_CREDITS);
-               if (IS_ERR(handle)) {
-                       ret = PTR_ERR(handle);
-                       goto out;
-               }
                if (final_size > inode->i_size) {
+                       /* Credits for sb + inode write */
+                       handle = ext3_journal_start(inode, 2);
+                       if (IS_ERR(handle)) {
+                               ret = PTR_ERR(handle);
+                               goto out;
+                       }
                        ret = ext3_orphan_add(handle, inode);
-                       if (ret)
-                               goto out_stop;
+                       if (ret) {
+                               ext3_journal_stop(handle);
+                               goto out;
+                       }
                        orphan = 1;
                        ei->i_disksize = inode->i_size;
+                       ext3_journal_stop(handle);
                }
        }
 
@@ -1715,18 +1708,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
                                 offset, nr_segs,
                                 ext3_get_block, NULL);
 
-       /*
-        * Reacquire the handle: ext3_get_block() can restart the transaction
-        */
-       handle = ext3_journal_current_handle();
-
-out_stop:
-       if (handle) {
+       if (orphan) {
                int err;
 
-               if (orphan && inode->i_nlink)
+               /* Credits for sb + inode write */
+               handle = ext3_journal_start(inode, 2);
+               if (IS_ERR(handle)) {
+                       /* This is really bad luck. We've written the data
+                        * but cannot extend i_size. Bail out and pretend
+                        * the write failed... */
+                       ret = PTR_ERR(handle);
+                       goto out;
+               }
+               if (inode->i_nlink)
                        ext3_orphan_del(handle, inode);
-               if (orphan && ret > 0) {
+               if (ret > 0) {
                        loff_t end = offset + ret;
                        if (end > inode->i_size) {
                                ei->i_disksize = end;
index 4ab6f76..92b83b0 100644 (file)
@@ -860,14 +860,10 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
        int nblocks, i, err;
        struct inode *dir = dentry->d_parent->d_inode;
        int namelen;
-       const u8 *name;
-       unsigned blocksize;
 
        *res_dir = NULL;
        sb = dir->i_sb;
-       blocksize = sb->s_blocksize;
        namelen = dentry->d_name.len;
-       name = dentry->d_name.name;
        if (namelen > EXT3_NAME_LEN)
                return NULL;
        if (is_dx(dir)) {
index f3675cc..343677e 100644 (file)
@@ -575,16 +575,16 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
            le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) {
                seq_printf(seq, ",resgid=%u", sbi->s_resgid);
        }
-       if (test_opt(sb, ERRORS_CONT)) {
+       if (test_opt(sb, ERRORS_RO)) {
                int def_errors = le16_to_cpu(es->s_errors);
 
                if (def_errors == EXT3_ERRORS_PANIC ||
-                   def_errors == EXT3_ERRORS_RO) {
-                       seq_puts(seq, ",errors=continue");
+                   def_errors == EXT3_ERRORS_CONTINUE) {
+                       seq_puts(seq, ",errors=remount-ro");
                }
        }
-       if (test_opt(sb, ERRORS_RO))
-               seq_puts(seq, ",errors=remount-ro");
+       if (test_opt(sb, ERRORS_CONT))
+               seq_puts(seq, ",errors=continue");
        if (test_opt(sb, ERRORS_PANIC))
                seq_puts(seq, ",errors=panic");
        if (test_opt(sb, NO_UID32))
@@ -1252,28 +1252,24 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
 }
 
 /* Called at mount-time, super-block is locked */
-static int ext3_check_descriptors (struct super_block * sb)
+static int ext3_check_descriptors(struct super_block *sb)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
        ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        ext3_fsblk_t last_block;
-       struct ext3_group_desc * gdp = NULL;
-       int desc_block = 0;
        int i;
 
        ext3_debug ("Checking group descriptors");
 
-       for (i = 0; i < sbi->s_groups_count; i++)
-       {
+       for (i = 0; i < sbi->s_groups_count; i++) {
+               struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL);
+
                if (i == sbi->s_groups_count - 1)
                        last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
                else
                        last_block = first_block +
                                (EXT3_BLOCKS_PER_GROUP(sb) - 1);
 
-               if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
-                       gdp = (struct ext3_group_desc *)
-                                       sbi->s_group_desc[desc_block++]->b_data;
                if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
                    le32_to_cpu(gdp->bg_block_bitmap) > last_block)
                {
@@ -1306,7 +1302,6 @@ static int ext3_check_descriptors (struct super_block * sb)
                        return 0;
                }
                first_block += EXT3_BLOCKS_PER_GROUP(sb);
-               gdp++;
        }
 
        sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb));
@@ -1583,10 +1578,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
 
        if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
-       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
-               set_opt(sbi->s_mount_opt, ERRORS_RO);
-       else
+       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_CONTINUE)
                set_opt(sbi->s_mount_opt, ERRORS_CONT);
+       else
+               set_opt(sbi->s_mount_opt, ERRORS_RO);
 
        sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
index ac75ea9..0737e05 100644 (file)
@@ -1700,7 +1700,7 @@ retry_alloc:
 
        /*
         * Now search the rest of the groups.  We assume that
-        * i and gdp correctly point to the last group visited.
+        * group_no and gdp correctly point to the last group visited.
         */
        for (bgi = 0; bgi < ngroups; bgi++) {
                group_no++;
@@ -2011,11 +2011,7 @@ static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb,
 static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
                                        ext4_group_t group)
 {
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
-                       !ext4_group_sparse(group))
-               return 0;
-       return EXT4_SB(sb)->s_gdb_count;
+       return ext4_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0;
 }
 
 /**
index 05c4145..0e9055c 100644 (file)
@@ -429,16 +429,13 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
  *     ext4_find_goal - find a prefered place for allocation.
  *     @inode: owner
  *     @block:  block we want
- *     @chain:  chain of indirect blocks
  *     @partial: pointer to the last triple within a chain
- *     @goal:  place to store the result.
  *
  *     Normally this function find the prefered place for block allocation,
- *     stores it in *@goal and returns zero.
+ *     returns it.
  */
-
 static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block,
-               Indirect chain[4], Indirect *partial)
+               Indirect *partial)
 {
        struct ext4_block_alloc_info *block_i;
 
@@ -839,7 +836,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
        if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
                ext4_init_block_alloc_info(inode);
 
-       goal = ext4_find_goal(inode, iblock, chain, partial);
+       goal = ext4_find_goal(inode, iblock, partial);
 
        /* the number of blocks need to allocate for [d,t]indirect blocks */
        indirect_blks = (chain + depth) - partial - 1;
index 055a0cd..c89bb87 100644 (file)
@@ -1458,7 +1458,7 @@ int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group,
 }
 
 /* Called at mount-time, super-block is locked */
-static int ext4_check_descriptors (struct super_block * sb)
+static int ext4_check_descriptors(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
@@ -1466,8 +1466,6 @@ static int ext4_check_descriptors (struct super_block * sb)
        ext4_fsblk_t block_bitmap;
        ext4_fsblk_t inode_bitmap;
        ext4_fsblk_t inode_table;
-       struct ext4_group_desc * gdp = NULL;
-       int desc_block = 0;
        int flexbg_flag = 0;
        ext4_group_t i;
 
@@ -1476,17 +1474,15 @@ static int ext4_check_descriptors (struct super_block * sb)
 
        ext4_debug ("Checking group descriptors");
 
-       for (i = 0; i < sbi->s_groups_count; i++)
-       {
+       for (i = 0; i < sbi->s_groups_count; i++) {
+               struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
+
                if (i == sbi->s_groups_count - 1 || flexbg_flag)
                        last_block = ext4_blocks_count(sbi->s_es) - 1;
                else
                        last_block = first_block +
                                (EXT4_BLOCKS_PER_GROUP(sb) - 1);
 
-               if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0)
-                       gdp = (struct ext4_group_desc *)
-                                       sbi->s_group_desc[desc_block++]->b_data;
                block_bitmap = ext4_block_bitmap(sb, gdp);
                if (block_bitmap < first_block || block_bitmap > last_block)
                {
@@ -1524,8 +1520,6 @@ static int ext4_check_descriptors (struct super_block * sb)
                }
                if (!flexbg_flag)
                        first_block += EXT4_BLOCKS_PER_GROUP(sb);
-               gdp = (struct ext4_group_desc *)
-                       ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
        }
 
        ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
index 69a83b5..c614175 100644 (file)
@@ -155,6 +155,42 @@ out:
        return err;
 }
 
+static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
+{
+       mode_t req = mode & ~S_IFMT;
+
+       /*
+        * Of the r and x bits, all (subject to umask) must be present. Of the
+        * w bits, either all (subject to umask) or none must be present.
+        */
+
+       if (S_ISREG(mode)) {
+               req &= ~sbi->options.fs_fmask;
+
+               if ((req & (S_IRUGO | S_IXUGO)) !=
+                   ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
+                       return -EPERM;
+
+               if ((req & S_IWUGO) != 0 &&
+                   (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
+                       return -EPERM;
+       } else if (S_ISDIR(mode)) {
+               req &= ~sbi->options.fs_dmask;
+
+               if ((req & (S_IRUGO | S_IXUGO)) !=
+                   ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
+                       return -EPERM;
+
+               if ((req & S_IWUGO) != 0 &&
+                   (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
+                       return -EPERM;
+       } else {
+               return -EPERM;
+       }
+
+       return 0;
+}
+
 int fat_notify_change(struct dentry *dentry, struct iattr *attr)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -186,9 +222,7 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
        if (((attr->ia_valid & ATTR_UID) &&
             (attr->ia_uid != sbi->options.fs_uid)) ||
            ((attr->ia_valid & ATTR_GID) &&
-            (attr->ia_gid != sbi->options.fs_gid)) ||
-           ((attr->ia_valid & ATTR_MODE) &&
-            (attr->ia_mode & ~MSDOS_VALID_MODE)))
+            (attr->ia_gid != sbi->options.fs_gid)))
                error = -EPERM;
 
        if (error) {
@@ -196,6 +230,13 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
                        error = 0;
                goto out;
        }
+
+       if (attr->ia_valid & ATTR_MODE) {
+               error = check_mode(sbi, attr->ia_mode);
+               if (error != 0 && !sbi->options.quiet)
+                       goto out;
+       }
+
        error = inode_setattr(inode, attr);
        if (error)
                goto out;
index 920a576..24c0aaa 100644 (file)
@@ -1295,10 +1295,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
 
                fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data;
                if (!IS_FSINFO(fsinfo)) {
-                       printk(KERN_WARNING
-                              "FAT: Did not find valid FSINFO signature.\n"
-                              "     Found signature1 0x%08x signature2 0x%08x"
-                              " (sector = %lu)\n",
+                       printk(KERN_WARNING "FAT: Invalid FSINFO signature: "
+                              "0x%08x, 0x%08x (sector = %lu)\n",
                               le32_to_cpu(fsinfo->signature1),
                               le32_to_cpu(fsinfo->signature2),
                               sbi->fsinfo_sector);
index 308f2b6..61f2351 100644 (file)
@@ -55,9 +55,8 @@ void fat_clusters_flush(struct super_block *sb)
        fsinfo = (struct fat_boot_fsinfo *)bh->b_data;
        /* Sanity check */
        if (!IS_FSINFO(fsinfo)) {
-               printk(KERN_ERR "FAT: Did not find valid FSINFO signature.\n"
-                      "     Found signature1 0x%08x signature2 0x%08x"
-                      " (sector = %lu)\n",
+               printk(KERN_ERR "FAT: Invalid FSINFO signature: "
+                      "0x%08x, 0x%08x (sector = %lu)\n",
                       le32_to_cpu(fsinfo->signature1),
                       le32_to_cpu(fsinfo->signature2),
                       sbi->fsinfo_sector);
index c5575de..5110acb 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -24,6 +24,8 @@ struct fdtable_defer {
        struct fdtable *next;
 };
 
+int sysctl_nr_open __read_mostly = 1024*1024;
+
 /*
  * We use this list to defer free fdtables that have vmalloced
  * sets/arrays. By keeping a per-cpu list, we avoid having to embed
@@ -147,8 +149,8 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
        nr /= (1024 / sizeof(struct file *));
        nr = roundup_pow_of_two(nr + 1);
        nr *= (1024 / sizeof(struct file *));
-       if (nr > NR_OPEN)
-               nr = NR_OPEN;
+       if (nr > sysctl_nr_open)
+               nr = sysctl_nr_open;
 
        fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
        if (!fdt)
@@ -233,7 +235,7 @@ int expand_files(struct files_struct *files, int nr)
        if (nr < fdt->max_fds)
                return 0;
        /* Can we expand? */
-       if (nr >= NR_OPEN)
+       if (nr >= sysctl_nr_open)
                return -EMFILE;
 
        /* All good, so we try */
index 0b30640..db80ce9 100644 (file)
@@ -515,8 +515,7 @@ writeback_inodes(struct writeback_control *wbc)
        might_sleep();
        spin_lock(&sb_lock);
 restart:
-       sb = sb_entry(super_blocks.prev);
-       for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
+       list_for_each_entry_reverse(sb, &super_blocks, s_list) {
                if (sb_has_dirty_inodes(sb)) {
                        /* we're making our own get_super here */
                        sb->s_count++;
@@ -581,10 +580,8 @@ static void set_sb_syncing(int val)
 {
        struct super_block *sb;
        spin_lock(&sb_lock);
-       sb = sb_entry(super_blocks.prev);
-       for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
+       list_for_each_entry_reverse(sb, &super_blocks, s_list)
                sb->s_syncing = val;
-       }
        spin_unlock(&sb_lock);
 }
 
index db534bc..af63980 100644 (file)
@@ -201,6 +201,55 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
        }
 }
 
+static unsigned len_args(unsigned numargs, struct fuse_arg *args)
+{
+       unsigned nbytes = 0;
+       unsigned i;
+
+       for (i = 0; i < numargs; i++)
+               nbytes += args[i].size;
+
+       return nbytes;
+}
+
+static u64 fuse_get_unique(struct fuse_conn *fc)
+{
+       fc->reqctr++;
+       /* zero is special */
+       if (fc->reqctr == 0)
+               fc->reqctr = 1;
+
+       return fc->reqctr;
+}
+
+static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
+{
+       req->in.h.unique = fuse_get_unique(fc);
+       req->in.h.len = sizeof(struct fuse_in_header) +
+               len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
+       list_add_tail(&req->list, &fc->pending);
+       req->state = FUSE_REQ_PENDING;
+       if (!req->waiting) {
+               req->waiting = 1;
+               atomic_inc(&fc->num_waiting);
+       }
+       wake_up(&fc->waitq);
+       kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+}
+
+static void flush_bg_queue(struct fuse_conn *fc)
+{
+       while (fc->active_background < FUSE_MAX_BACKGROUND &&
+              !list_empty(&fc->bg_queue)) {
+               struct fuse_req *req;
+
+               req = list_entry(fc->bg_queue.next, struct fuse_req, list);
+               list_del(&req->list);
+               fc->active_background++;
+               queue_request(fc, req);
+       }
+}
+
 /*
  * This function is called when a request is finished.  Either a reply
  * has arrived or it was aborted (and not yet sent) or some error
@@ -229,6 +278,8 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
                        clear_bdi_congested(&fc->bdi, WRITE);
                }
                fc->num_background--;
+               fc->active_background--;
+               flush_bg_queue(fc);
        }
        spin_unlock(&fc->lock);
        wake_up(&req->waitq);
@@ -320,42 +371,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
        }
 }
 
-static unsigned len_args(unsigned numargs, struct fuse_arg *args)
-{
-       unsigned nbytes = 0;
-       unsigned i;
-
-       for (i = 0; i < numargs; i++)
-               nbytes += args[i].size;
-
-       return nbytes;
-}
-
-static u64 fuse_get_unique(struct fuse_conn *fc)
- {
-       fc->reqctr++;
-       /* zero is special */
-       if (fc->reqctr == 0)
-               fc->reqctr = 1;
-
-       return fc->reqctr;
-}
-
-static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
-{
-       req->in.h.unique = fuse_get_unique(fc);
-       req->in.h.len = sizeof(struct fuse_in_header) +
-               len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
-       list_add_tail(&req->list, &fc->pending);
-       req->state = FUSE_REQ_PENDING;
-       if (!req->waiting) {
-               req->waiting = 1;
-               atomic_inc(&fc->num_waiting);
-       }
-       wake_up(&fc->waitq);
-       kill_fasync(&fc->fasync, SIGIO, POLL_IN);
-}
-
 void request_send(struct fuse_conn *fc, struct fuse_req *req)
 {
        req->isreply = 1;
@@ -375,20 +390,26 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req)
        spin_unlock(&fc->lock);
 }
 
+static void request_send_nowait_locked(struct fuse_conn *fc,
+                                      struct fuse_req *req)
+{
+       req->background = 1;
+       fc->num_background++;
+       if (fc->num_background == FUSE_MAX_BACKGROUND)
+               fc->blocked = 1;
+       if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
+               set_bdi_congested(&fc->bdi, READ);
+               set_bdi_congested(&fc->bdi, WRITE);
+       }
+       list_add_tail(&req->list, &fc->bg_queue);
+       flush_bg_queue(fc);
+}
+
 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
 {
        spin_lock(&fc->lock);
        if (fc->connected) {
-               req->background = 1;
-               fc->num_background++;
-               if (fc->num_background == FUSE_MAX_BACKGROUND)
-                       fc->blocked = 1;
-               if (fc->num_background == FUSE_CONGESTION_THRESHOLD) {
-                       set_bdi_congested(&fc->bdi, READ);
-                       set_bdi_congested(&fc->bdi, WRITE);
-               }
-
-               queue_request(fc, req);
+               request_send_nowait_locked(fc, req);
                spin_unlock(&fc->lock);
        } else {
                req->out.h.error = -ENOTCONN;
index 80d2f52..f56f91b 100644 (file)
@@ -416,6 +416,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
        fuse_put_request(fc, forget_req);
        d_instantiate(entry, inode);
        fuse_change_entry_timeout(entry, &outentry);
+       fuse_invalidate_attr(dir);
        file = lookup_instantiate_filp(nd, entry, generic_file_open);
        if (IS_ERR(file)) {
                ff->fh = outopen.fh;
index bb05d22..676b0bc 100644 (file)
@@ -77,8 +77,8 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff)
 
 static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-       dput(req->dentry);
-       mntput(req->vfsmount);
+       dput(req->misc.release.dentry);
+       mntput(req->misc.release.vfsmount);
        fuse_put_request(fc, req);
 }
 
@@ -86,7 +86,8 @@ static void fuse_file_put(struct fuse_file *ff)
 {
        if (atomic_dec_and_test(&ff->count)) {
                struct fuse_req *req = ff->reserved_req;
-               struct fuse_conn *fc = get_fuse_conn(req->dentry->d_inode);
+               struct inode *inode = req->misc.release.dentry->d_inode;
+               struct fuse_conn *fc = get_fuse_conn(inode);
                req->end = fuse_release_end;
                request_send_background(fc, req);
                kfree(ff);
@@ -137,7 +138,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
 void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode)
 {
        struct fuse_req *req = ff->reserved_req;
-       struct fuse_release_in *inarg = &req->misc.release_in;
+       struct fuse_release_in *inarg = &req->misc.release.in;
 
        inarg->fh = ff->fh;
        inarg->flags = flags;
@@ -153,13 +154,14 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir)
        struct fuse_file *ff = file->private_data;
        if (ff) {
                struct fuse_conn *fc = get_fuse_conn(inode);
+               struct fuse_req *req = ff->reserved_req;
 
                fuse_release_fill(ff, get_node_id(inode), file->f_flags,
                                  isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
 
                /* Hold vfsmount and dentry until release is finished */
-               ff->reserved_req->vfsmount = mntget(file->f_path.mnt);
-               ff->reserved_req->dentry = dget(file->f_path.dentry);
+               req->misc.release.vfsmount = mntget(file->f_path.mnt);
+               req->misc.release.dentry = dget(file->f_path.dentry);
 
                spin_lock(&fc->lock);
                list_del(&ff->write_entry);
index 3ab8a30..67aaf6e 100644 (file)
@@ -215,7 +215,11 @@ struct fuse_req {
        /** Data for asynchronous requests */
        union {
                struct fuse_forget_in forget_in;
-               struct fuse_release_in release_in;
+               struct {
+                       struct fuse_release_in in;
+                       struct vfsmount *vfsmount;
+                       struct dentry *dentry;
+               } release;
                struct fuse_init_in init_in;
                struct fuse_init_out init_out;
                struct fuse_read_in read_in;
@@ -238,12 +242,6 @@ struct fuse_req {
        /** File used in the request (or NULL) */
        struct fuse_file *ff;
 
-       /** vfsmount used in release */
-       struct vfsmount *vfsmount;
-
-       /** dentry used in release */
-       struct dentry *dentry;
-
        /** Request completion callback */
        void (*end)(struct fuse_conn *, struct fuse_req *);
 
@@ -298,6 +296,12 @@ struct fuse_conn {
        /** Number of requests currently in the background */
        unsigned num_background;
 
+       /** Number of background requests currently queued for userspace */
+       unsigned active_background;
+
+       /** The list of background requests set aside for later queuing */
+       struct list_head bg_queue;
+
        /** Pending interrupts */
        struct list_head interrupts;
 
index e5e80d1..c90f633 100644 (file)
@@ -465,6 +465,7 @@ static struct fuse_conn *new_conn(void)
                INIT_LIST_HEAD(&fc->processing);
                INIT_LIST_HEAD(&fc->io);
                INIT_LIST_HEAD(&fc->interrupts);
+               INIT_LIST_HEAD(&fc->bg_queue);
                atomic_set(&fc->num_waiting, 0);
                fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
                fc->bdi.unplug_io_fn = default_unplug_io_fn;
index f8452a0..4129cdb 100644 (file)
@@ -52,9 +52,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
                rec = (e + b) / 2;
                len = hfs_brec_lenoff(bnode, rec, &off);
                keylen = hfs_brec_keylen(bnode, rec);
-               if (keylen == HFS_BAD_KEYLEN) {
+               if (keylen == 0) {
                        res = -EINVAL;
-                       goto done;
+                       goto fail;
                }
                hfs_bnode_read(bnode, fd->key, off, keylen);
                cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
@@ -71,9 +71,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
        if (rec != e && e >= 0) {
                len = hfs_brec_lenoff(bnode, e, &off);
                keylen = hfs_brec_keylen(bnode, e);
-               if (keylen == HFS_BAD_KEYLEN) {
+               if (keylen == 0) {
                        res = -EINVAL;
-                       goto done;
+                       goto fail;
                }
                hfs_bnode_read(bnode, fd->key, off, keylen);
        }
@@ -83,6 +83,7 @@ done:
        fd->keylength = keylen;
        fd->entryoffset = off + keylen;
        fd->entrylength = len - keylen;
+fail:
        return res;
 }
 
@@ -206,7 +207,7 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
 
        len = hfs_brec_lenoff(bnode, fd->record, &off);
        keylen = hfs_brec_keylen(bnode, fd->record);
-       if (keylen == HFS_BAD_KEYLEN) {
+       if (keylen == 0) {
                res = -EINVAL;
                goto out;
        }
index 8626ee3..878bf25 100644 (file)
@@ -49,14 +49,14 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
                        if (retval > node->tree->max_key_len + 2) {
                                printk(KERN_ERR "hfs: keylen %d too large\n",
                                        retval);
-                               retval = HFS_BAD_KEYLEN;
+                               retval = 0;
                        }
                } else {
                        retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
                        if (retval > node->tree->max_key_len + 1) {
                                printk(KERN_ERR "hfs: keylen %d too large\n",
                                        retval);
-                               retval = HFS_BAD_KEYLEN;
+                               retval = 0;
                        }
                }
        }
index 110dd35..24cf6fc 100644 (file)
@@ -81,15 +81,23 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
                goto fail_page;
        if (!tree->node_count)
                goto fail_page;
-       if ((id == HFS_EXT_CNID) && (tree->max_key_len != HFS_MAX_EXT_KEYLEN)) {
-               printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
-                       tree->max_key_len);
-               goto fail_page;
-       }
-       if ((id == HFS_CAT_CNID) && (tree->max_key_len != HFS_MAX_CAT_KEYLEN)) {
-               printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
-                       tree->max_key_len);
-               goto fail_page;
+       switch (id) {
+       case HFS_EXT_CNID:
+               if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) {
+                       printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
+                               tree->max_key_len);
+                       goto fail_page;
+               }
+               break;
+       case HFS_CAT_CNID:
+               if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) {
+                       printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
+                               tree->max_key_len);
+                       goto fail_page;
+               }
+               break;
+       default:
+               BUG();
        }
 
        tree->node_size_shift = ffs(size) - 1;
index c6aae61..6f194d0 100644 (file)
@@ -28,8 +28,6 @@
 #define HFS_MAX_NAMELEN                128
 #define HFS_MAX_VALENCE                32767U
 
-#define HFS_BAD_KEYLEN         0xFF
-
 /* Meanings of the drAtrb field of the MDB,
  * Reference: _Inside Macintosh: Files_ p. 2-61
  */
index 16cbd90..32de44e 100644 (file)
@@ -6,7 +6,7 @@
  * This file may be distributed under the terms of the GNU General Public License.
  *
  * This file contains hfs_read_super(), some of the super_ops and
- * init_module() and cleanup_module(). The remaining super_ops are in
+ * init_hfs_fs() and exit_hfs_fs().  The remaining super_ops are in
  * inode.c since they deal with inodes.
  *
  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
index 2c5b921..690e725 100644 (file)
@@ -168,20 +168,14 @@ static void set_dentry_child_flags(struct inode *inode, int watched)
                struct dentry *child;
 
                list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
-                       if (!child->d_inode) {
-                               WARN_ON(child->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
+                       if (!child->d_inode)
                                continue;
-                       }
+
                        spin_lock(&child->d_lock);
-                       if (watched) {
-                               WARN_ON(child->d_flags &
-                                               DCACHE_INOTIFY_PARENT_WATCHED);
+                       if (watched)
                                child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
-                       } else {
-                               WARN_ON(!(child->d_flags &
-                                       DCACHE_INOTIFY_PARENT_WATCHED));
-                               child->d_flags&=~DCACHE_INOTIFY_PARENT_WATCHED;
-                       }
+                       else
+                               child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED;
                        spin_unlock(&child->d_lock);
                }
        }
@@ -253,7 +247,6 @@ void inotify_d_instantiate(struct dentry *entry, struct inode *inode)
        if (!inode)
                return;
 
-       WARN_ON(entry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED);
        spin_lock(&entry->d_lock);
        parent = entry->d_parent;
        if (parent->d_inode && inotify_inode_watched(parent->d_inode))
@@ -627,6 +620,7 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch,
                      struct inode *inode, u32 mask)
 {
        int ret = 0;
+       int newly_watched;
 
        /* don't allow invalid bits: we don't want flags set */
        mask &= IN_ALL_EVENTS | IN_ONESHOT;
@@ -653,12 +647,18 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch,
         */
        watch->inode = igrab(inode);
 
-       if (!inotify_inode_watched(inode))
-               set_dentry_child_flags(inode, 1);
-
        /* Add the watch to the handle's and the inode's list */
+       newly_watched = !inotify_inode_watched(inode);
        list_add(&watch->h_list, &ih->watches);
        list_add(&watch->i_list, &inode->inotify_watches);
+       /*
+        * Set child flags _after_ adding the watch, so there is no race
+        * windows where newly instantiated children could miss their parent's
+        * watched flag.
+        */
+       if (newly_watched)
+               set_dentry_child_flags(inode, 1);
+
 out:
        mutex_unlock(&ih->mutex);
        mutex_unlock(&inode->inotify_mutex);
index 5e00933..a336c97 100644 (file)
@@ -79,6 +79,7 @@ struct inotify_device {
        atomic_t                count;          /* reference count */
        struct user_struct      *user;          /* user who opened this dev */
        struct inotify_handle   *ih;            /* inotify handle */
+       struct fasync_struct    *fa;            /* async notification */
        unsigned int            queue_size;     /* size of the queue (bytes) */
        unsigned int            event_count;    /* number of pending events */
        unsigned int            max_events;     /* maximum number of events */
@@ -247,6 +248,19 @@ inotify_dev_get_event(struct inotify_device *dev)
        return list_entry(dev->events.next, struct inotify_kernel_event, list);
 }
 
+/*
+ * inotify_dev_get_last_event - return the last event in the given dev's queue
+ *
+ * Caller must hold dev->ev_mutex.
+ */
+static inline struct inotify_kernel_event *
+inotify_dev_get_last_event(struct inotify_device *dev)
+{
+       if (list_empty(&dev->events))
+               return NULL;
+       return list_entry(dev->events.prev, struct inotify_kernel_event, list);
+}
+
 /*
  * inotify_dev_queue_event - event handler registered with core inotify, adds
  * a new event to the given device
@@ -273,7 +287,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask,
                put_inotify_watch(w); /* final put */
 
        /* coalescing: drop this event if it is a dupe of the previous */
-       last = inotify_dev_get_event(dev);
+       last = inotify_dev_get_last_event(dev);
        if (last && last->event.mask == mask && last->event.wd == wd &&
                        last->event.cookie == cookie) {
                const char *lastname = last->name;
@@ -302,6 +316,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask,
        dev->queue_size += sizeof(struct inotify_event) + kevent->event.len;
        list_add_tail(&kevent->list, &dev->events);
        wake_up_interruptible(&dev->wq);
+       kill_fasync(&dev->fa, SIGIO, POLL_IN);
 
 out:
        mutex_unlock(&dev->ev_mutex);
@@ -490,6 +505,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
        return ret;
 }
 
+static int inotify_fasync(int fd, struct file *file, int on)
+{
+       struct inotify_device *dev = file->private_data;
+
+       return fasync_helper(fd, file, on, &dev->fa) >= 0 ? 0 : -EIO;
+}
+
 static int inotify_release(struct inode *ignored, struct file *file)
 {
        struct inotify_device *dev = file->private_data;
@@ -502,6 +524,9 @@ static int inotify_release(struct inode *ignored, struct file *file)
                inotify_dev_event_dequeue(dev);
        mutex_unlock(&dev->ev_mutex);
 
+       if (file->f_flags & FASYNC)
+               inotify_fasync(-1, file, 0);
+
        /* free this device: the put matching the get in inotify_init() */
        put_inotify_dev(dev);
 
@@ -530,6 +555,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
 static const struct file_operations inotify_fops = {
        .poll           = inotify_poll,
        .read           = inotify_read,
+       .fasync         = inotify_fasync,
        .release        = inotify_release,
        .unlocked_ioctl = inotify_ioctl,
        .compat_ioctl   = inotify_ioctl,
@@ -577,6 +603,7 @@ asmlinkage long sys_inotify_init(void)
                goto out_free_dev;
        }
        dev->ih = ih;
+       dev->fa = NULL;
 
        filp->f_op = &inotify_fops;
        filp->f_path.mnt = mntget(inotify_mnt);
index 5d14243..3943a89 100644 (file)
@@ -1457,7 +1457,7 @@ static const char *journal_dev_name(journal_t *journal, char *buffer)
  * Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
  * and don't attempt to make any other journal updates.
  */
-void __journal_abort_hard(journal_t *journal)
+static void __journal_abort_hard(journal_t *journal)
 {
        transaction_t *transaction;
        char b[BDEVNAME_SIZE];
index c5d9694..2b8edf4 100644 (file)
@@ -354,7 +354,7 @@ static int do_one_pass(journal_t *journal,
                struct buffer_head *    obh;
                struct buffer_head *    nbh;
 
-               cond_resched();         /* We're under lock_kernel() */
+               cond_resched();
 
                /* If we already know where to stop the log traversal,
                 * check right now that we haven't gone past the end of
index 9216806..d36356f 100644 (file)
@@ -397,7 +397,7 @@ static int do_one_pass(journal_t *journal,
                struct buffer_head *    obh;
                struct buffer_head *    nbh;
 
-               cond_resched();         /* We're under lock_kernel() */
+               cond_resched();
 
                /* If we already know where to stop the log traversal,
                 * check right now that we haven't gone past the end of
index 73e2e66..241cff4 100644 (file)
@@ -2188,6 +2188,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
 
        /* We don't d_delete() NFS sillyrenamed files--they still exist. */
        if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
+               fsnotify_link_count(dentry->d_inode);
                d_delete(dentry);
        }
 
@@ -2360,7 +2361,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        error = dir->i_op->link(old_dentry, dir, new_dentry);
        mutex_unlock(&old_dentry->d_inode->i_mutex);
        if (!error)
-               fsnotify_create(dir, new_dentry);
+               fsnotify_link(dir, old_dentry->d_inode, new_dentry);
        return error;
 }
 
index 61bf376..e9c10cd 100644 (file)
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/ramfs.h>
+#include <linux/log2.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include "pnode.h"
 #include "internal.h"
 
+#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
+#define HASH_SIZE (1UL << HASH_SHIFT)
+
 /* spinlock for vfsmount related operations, inplace of dcache_lock */
 __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
 
 static int event;
 
 static struct list_head *mount_hashtable __read_mostly;
-static int hash_mask __read_mostly, hash_bits __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
 static struct rw_semaphore namespace_sem;
 
@@ -48,8 +51,8 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
        unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
        tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
-       tmp = tmp + (tmp >> hash_bits);
-       return tmp & hash_mask;
+       tmp = tmp + (tmp >> HASH_SHIFT);
+       return tmp & (HASH_SIZE - 1);
 }
 
 struct vfsmount *alloc_vfsmnt(const char *name)
@@ -1813,9 +1816,7 @@ static void __init init_mount_tree(void)
 
 void __init mnt_init(void)
 {
-       struct list_head *d;
-       unsigned int nr_hash;
-       int i;
+       unsigned u;
        int err;
 
        init_rwsem(&namespace_sem);
@@ -1828,35 +1829,11 @@ void __init mnt_init(void)
        if (!mount_hashtable)
                panic("Failed to allocate mount hash table\n");
 
-       /*
-        * Find the power-of-two list-heads that can fit into the allocation..
-        * We don't guarantee that "sizeof(struct list_head)" is necessarily
-        * a power-of-two.
-        */
-       nr_hash = PAGE_SIZE / sizeof(struct list_head);
-       hash_bits = 0;
-       do {
-               hash_bits++;
-       } while ((nr_hash >> hash_bits) != 0);
-       hash_bits--;
+       printk("Mount-cache hash table entries: %lu\n", HASH_SIZE);
+
+       for (u = 0; u < HASH_SIZE; u++)
+               INIT_LIST_HEAD(&mount_hashtable[u]);
 
-       /*
-        * Re-calculate the actual number of entries and the mask
-        * from the number of bits we can fit.
-        */
-       nr_hash = 1UL << hash_bits;
-       hash_mask = nr_hash - 1;
-
-       printk("Mount-cache hash table entries: %d\n", nr_hash);
-
-       /* And initialize the newly allocated array */
-       d = mount_hashtable;
-       i = nr_hash;
-       do {
-               INIT_LIST_HEAD(d);
-               d++;
-               i--;
-       } while (i);
        err = sysfs_init();
        if (err)
                printk(KERN_WARNING "%s: sysfs_init error: %d\n",
index e1cb70c..eff1f18 100644 (file)
@@ -987,7 +987,7 @@ static struct file_system_type ncp_fs_type = {
 static int __init init_ncp_fs(void)
 {
        int err;
-       DPRINTK("ncpfs: init_module called\n");
+       DPRINTK("ncpfs: init_ncp_fs called\n");
 
        err = init_inodecache();
        if (err)
@@ -1004,7 +1004,7 @@ out1:
 
 static void __exit exit_ncp_fs(void)
 {
-       DPRINTK("ncpfs: cleanup_module called\n");
+       DPRINTK("ncpfs: exit_ncp_fs called\n");
        unregister_filesystem(&ncp_fs_type);
        destroy_inodecache();
 }
index a99acd8..cb5f0a3 100644 (file)
@@ -198,7 +198,7 @@ config LDM_DEBUG
 
 config SGI_PARTITION
        bool "SGI partition support" if PARTITION_ADVANCED
-       default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN))
+       default y if DEFAULT_SGI_PARTITION
        help
          Say Y here if you would like to be able to read the hard disk
          partition table format used by SGI machines.
index 89940f2..05ba692 100644 (file)
@@ -83,6 +83,8 @@ void change_mnt_propagation(struct vfsmount *mnt, int type)
                mnt->mnt_master = NULL;
                if (type == MS_UNBINDABLE)
                        mnt->mnt_flags |= MNT_UNBINDABLE;
+               else
+                       mnt->mnt_flags &= ~MNT_UNBINDABLE;
        }
 }
 
index 51288db..2686592 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/mmzone.h>
 #include <linux/pagemap.h>
+#include <linux/interrupt.h>
 #include <linux/swap.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
@@ -64,7 +65,6 @@
  */
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
-extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_dma_list(char *);
 
@@ -84,10 +84,15 @@ static int loadavg_read_proc(char *page, char **start, off_t off,
 {
        int a, b, c;
        int len;
+       unsigned long seq;
+
+       do {
+               seq = read_seqbegin(&xtime_lock);
+               a = avenrun[0] + (FIXED_1/200);
+               b = avenrun[1] + (FIXED_1/200);
+               c = avenrun[2] + (FIXED_1/200);
+       } while (read_seqretry(&xtime_lock, seq));
 
-       a = avenrun[0] + (FIXED_1/200);
-       b = avenrun[1] + (FIXED_1/200);
-       c = avenrun[2] + (FIXED_1/200);
        len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
                LOAD_INT(a), LOAD_FRAC(a),
                LOAD_INT(b), LOAD_FRAC(b),
@@ -599,7 +604,6 @@ static void int_seq_stop(struct seq_file *f, void *v)
 }
 
 
-extern int show_interrupts(struct seq_file *f, void *v); /* In arch code */
 static struct seq_operations int_seq_ops = {
        .start = int_seq_start,
        .next  = int_seq_next,
index 5e7388b..740bb8c 100644 (file)
@@ -575,6 +575,8 @@ void print_block(struct buffer_head *bh, ...)       //int print_mode, int first, int l
                                        printk
                                            ("Block %llu contains unformatted data\n",
                                             (unsigned long long)bh->b_blocknr);
+
+       va_end(args);
 }
 
 static char print_tb_buf[2048];
index 1597f6b..a5bd23c 100644 (file)
@@ -1084,7 +1084,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
 }
 
 /* This is the implementation for the xattr plugin infrastructure */
-static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers);
+static LIST_HEAD(xattr_handlers);
 static DEFINE_RWLOCK(handler_lock);
 
 static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
index 47f4792..5633fe9 100644 (file)
@@ -739,7 +739,7 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
                        timeout_jiffies = -1;
                else
 #endif
-                       timeout_jiffies = msecs_to_jiffies(timeout_msecs);
+                       timeout_jiffies = msecs_to_jiffies(timeout_msecs) + 1;
        } else {
                /* Infinite (< 0) or no (0) timeout */
                timeout_jiffies = timeout_msecs;
index 2d3e107..cb2b63a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/anon_inodes.h>
 #include <linux/signalfd.h>
+#include <linux/syscalls.h>
 
 struct signalfd_ctx {
        sigset_t sigmask;
index e48bd82..e37fe4d 100644 (file)
@@ -329,9 +329,8 @@ smb_receive(struct smb_sb_info *server, struct smb_request *req)
        msg.msg_control = NULL;
 
        /* Dont repeat bytes and count available bufferspace */
-       rlen = smb_move_iov(&p, &num, iov, req->rq_bytes_recvd);
-       if (req->rq_rlen < rlen)
-               rlen = req->rq_rlen;
+       rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd),
+                       (req->rq_rlen - req->rq_bytes_recvd));
 
        result = kernel_recvmsg(sock, &msg, p, num, rlen, flags);
 
index b9912ec..e5588cd 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/utime.h>
+#include <linux/syscalls.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
index 04006c1..efd9a5e 100644 (file)
@@ -247,7 +247,7 @@ static inline u32 iop_desc_get_src_count(struct iop_adma_desc_slot *desc,
 }
 
 static inline void
-iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -257,13 +257,13 @@ iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
 
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 }
 
 static inline void
-iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -274,14 +274,15 @@ iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
        u_desc_ctrl.field.block_fill_en = 1;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 }
 
 /* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
 static inline void
-iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+                 unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -292,7 +293,7 @@ iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.src_select = src_cnt - 1;
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 
@@ -301,7 +302,8 @@ iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
 
 /* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
 static inline int
-iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
+                      unsigned long flags)
 {
        struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
        union {
@@ -314,7 +316,7 @@ iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
        u_desc_ctrl.field.zero_result = 1;
        u_desc_ctrl.field.status_write_back_en = 1;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->crc_addr = 0;
 
index 76fe5f6..bd85484 100644 (file)
 
 #define S3C2412_FRCPAT(x)      S3C2410_LCDREG(0xB4 + ((x)*4))
 
-#endif /* ___ASM_ARCH_REGS_LCD_H */
+/* general registers */
+
+/* base of the LCD registers, where INTPND, INTSRC and then INTMSK
+ * are available. */
 
+#define S3C2410_LCDINTBASE     S3C2410_LCDREG(0x54)
+#define S3C2412_LCDINTBASE     S3C2410_LCDREG(0x24)
 
+#define S3C24XX_LCDINTPND      (0x00)
+#define S3C24XX_LCDSRCPND      (0x04)
+#define S3C24XX_LCDINTMSK      (0x08)
 
+#endif /* ___ASM_ARCH_REGS_LCD_H */
index ba1dca8..7380373 100644 (file)
@@ -13,9 +13,6 @@
 #ifndef __ASM_ARCH_SPIGPIO_H
 #define __ASM_ARCH_SPIGPIO_H __FILE__
 
-struct s3c2410_spigpio_info;
-struct spi_board_info;
-
 struct s3c2410_spigpio_info {
        unsigned long            pin_clk;
        unsigned long            pin_mosi;
@@ -23,9 +20,6 @@ struct s3c2410_spigpio_info {
 
        int                      bus_num;
 
-       unsigned long            board_size;
-       struct spi_board_info   *board_info;
-
        void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
 };
 
index 4029a1a..7ca0ed9 100644 (file)
 #ifndef __ASM_ARCH_SPI_H
 #define __ASM_ARCH_SPI_H __FILE__
 
-struct s3c2410_spi_info;
-struct spi_board_info;
-
 struct s3c2410_spi_info {
        unsigned long            pin_cs;        /* simple gpio cs */
 
-       unsigned long            board_size;
-       struct spi_board_info   *board_info;
-
        void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
 };
 
index 10834b5..5c529e6 100644 (file)
@@ -414,7 +414,7 @@ static inline void iop3xx_aau_desc_set_src_addr(struct iop3xx_desc_aau *hw_desc,
 }
 
 static inline void
-iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop3xx_desc_dma *hw_desc = desc->hw_desc;
        union {
@@ -425,14 +425,14 @@ iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.mem_to_mem_en = 1;
        u_desc_ctrl.field.pci_transaction = 0xe; /* memory read block */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
        hw_desc->upper_pci_src_addr = 0;
        hw_desc->crc_addr = 0;
 }
 
 static inline void
-iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, unsigned long flags)
 {
        struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
        union {
@@ -443,12 +443,13 @@ iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
        u_desc_ctrl.value = 0;
        u_desc_ctrl.field.blk1_cmd_ctrl = 0x2; /* memory block fill */
        u_desc_ctrl.field.dest_write_en = 1;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
 }
 
 static inline u32
-iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt, int int_en)
+iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt,
+                    unsigned long flags)
 {
        int i, shift;
        u32 edcr;
@@ -509,21 +510,23 @@ iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt, int int_en)
 
        u_desc_ctrl.field.dest_write_en = 1;
        u_desc_ctrl.field.blk1_cmd_ctrl = 0x7; /* direct fill */
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
 
        return u_desc_ctrl.value;
 }
 
 static inline void
-iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+                 unsigned long flags)
 {
-       iop3xx_desc_init_xor(desc->hw_desc, src_cnt, int_en);
+       iop3xx_desc_init_xor(desc->hw_desc, src_cnt, flags);
 }
 
 /* return the number of operations */
 static inline int
-iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
+                      unsigned long flags)
 {
        int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op;
        struct iop3xx_desc_aau *hw_desc, *prev_hw_desc, *iter;
@@ -538,10 +541,10 @@ iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        for (i = 0, j = 0; (slot_cnt -= slots_per_op) >= 0;
                i += slots_per_op, j++) {
                iter = iop_hw_desc_slot_idx(hw_desc, i);
-               u_desc_ctrl.value = iop3xx_desc_init_xor(iter, src_cnt, int_en);
+               u_desc_ctrl.value = iop3xx_desc_init_xor(iter, src_cnt, flags);
                u_desc_ctrl.field.dest_write_en = 0;
                u_desc_ctrl.field.zero_result_en = 1;
-               u_desc_ctrl.field.int_en = int_en;
+               u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
                iter->desc_ctrl = u_desc_ctrl.value;
 
                /* for the subsequent descriptors preserve the store queue
@@ -559,7 +562,8 @@ iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
 }
 
 static inline void
-iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt,
+                      unsigned long flags)
 {
        struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
        union {
@@ -591,7 +595,7 @@ iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
        }
 
        u_desc_ctrl.field.dest_write_en = 0;
-       u_desc_ctrl.field.int_en = int_en;
+       u_desc_ctrl.field.int_en = flags & DMA_PREP_INTERRUPT;
        hw_desc->desc_ctrl = u_desc_ctrl.value;
 }
 
index cc3b2e3..a0ed9a9 100644 (file)
@@ -12,7 +12,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 #define udelay(n) (__builtin_constant_p(n) ? \
index 5e44ecb..187dcf3 100644 (file)
@@ -34,7 +34,6 @@ static inline cycles_t get_cycles (void)
        return 0;
 }
 
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER    1
+#define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif /* __ASM_AVR32_TIMEX_H */
index 1601d62..574fe56 100644 (file)
@@ -188,8 +188,6 @@ extern void blkfin_inv_cache_all(void);
 #define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
 #define page_to_bus(page)       ((page - mem_map) << PAGE_SHIFT)
 
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index 09204e4..1c1fa42 100644 (file)
@@ -18,6 +18,7 @@ typedef unsigned long cputime_t;
 #define cputime_lt(__a, __b)           ((__a) <  (__b))
 #define cputime_le(__a, __b)           ((__a) <= (__b))
 #define cputime_to_jiffies(__ct)       (__ct)
+#define cputime_to_scaled(__ct)                (__ct)
 #define jiffies_to_cputime(__hz)       (__hz)
 
 typedef u64 cputime64_t;
index 962cad7..8feeae1 100644 (file)
@@ -8,8 +8,6 @@ extern char _data[], _sdata[], _edata[];
 extern char __bss_start[], __bss_stop[];
 extern char __init_begin[], __init_end[];
 extern char _sinittext[], _einittext[];
-extern char _sextratext[] __attribute__((weak));
-extern char _eextratext[] __attribute__((weak));
 extern char _end[];
 extern char __per_cpu_start[], __per_cpu_end[];
 extern char __kprobes_text_start[], __kprobes_text_end[];
index 7543a57..26dc6cc 100644 (file)
@@ -302,8 +302,6 @@ static __inline__ void ctrl_outl(unsigned long b, unsigned long addr)
 /*
  * Macros used for converting between virtual and physical mappings.
  */
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index ee7d5ea..19cfd62 100644 (file)
@@ -10,8 +10,6 @@
 #include <asm/setup.h>
 #include <asm/page.h>
 
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index 164448d..9dd9e99 100644 (file)
@@ -12,7 +12,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 #define udelay(n) (__builtin_constant_p(n) ? \
index 778a4c5..0b604f0 100644 (file)
@@ -107,8 +107,6 @@ extern void *empty_zero_page;
 /* 64-bit machines, beware!  SRB. */
 #define SIZEOF_PTR_LOG2                               2
 
-#define mm_end_of_chunk(addr, len)     0
-
 extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode);
 
 /*
index 653d9b2..6adef1e 100644 (file)
@@ -172,8 +172,6 @@ extern void iounmap(void *addr);
 /*
  * Macros used for converting between virtual and physical mappings.
  */
-#define mm_ptov(vaddr)         ((void *) (vaddr))
-#define mm_vtop(vaddr)         ((unsigned long) (vaddr))
 #define phys_to_virt(vaddr)    ((void *) (vaddr))
 #define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
 
index 3108044..f42e623 100644 (file)
@@ -52,12 +52,26 @@ typedef u64 cputime64_t;
  * Convert cputime <-> jiffies
  */
 extern u64 __cputime_jiffies_factor;
+DECLARE_PER_CPU(unsigned long, cputime_last_delta);
+DECLARE_PER_CPU(unsigned long, cputime_scaled_last_delta);
 
 static inline unsigned long cputime_to_jiffies(const cputime_t ct)
 {
        return mulhdu(ct, __cputime_jiffies_factor);
 }
 
+/* Estimate the scaled cputime by scaling the real cputime based on
+ * the last scaled to real ratio */
+static inline cputime_t cputime_to_scaled(const cputime_t ct)
+{
+       if (cpu_has_feature(CPU_FTR_SPURR) &&
+           per_cpu(cputime_last_delta, smp_processor_id()))
+               return ct *
+                       per_cpu(cputime_scaled_last_delta, smp_processor_id())/
+                       per_cpu(cputime_last_delta, smp_processor_id());
+       return ct;
+}
+
 static inline cputime_t jiffies_to_cputime(const unsigned long jif)
 {
        cputime_t ct;
index 7a4374b..a7e06e2 100644 (file)
  *
  */
 
-/* see prep_setup_arch() for detailed informations */
-#if defined(CONFIG_SOUND_CS4232) && defined(CONFIG_PPC_PREP)
-extern long ppc_cs4232_dma, ppc_cs4232_dma2;
-#define SND_DMA1 ppc_cs4232_dma
-#define SND_DMA2 ppc_cs4232_dma2
-#else
-#define SND_DMA1 -1
-#define SND_DMA2 -1
-#endif
-
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE   0x00    /* 8 bit slave DMA, channels 0..3 */
 #define IO_DMA2_BASE   0xC0    /* 16 bit master DMA, ch 4(=slave input)..7 */
@@ -269,24 +259,15 @@ static __inline__ void set_dma_page(unsigned int dmanr, int pagenr)
                dma_outb(pagenr >> 8, DMA_HI_PAGE_3);
                break;
        case 5:
-               if (SND_DMA1 == 5 || SND_DMA2 == 5)
-                       dma_outb(pagenr, DMA_LO_PAGE_5);
-               else
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
                dma_outb(pagenr >> 8, DMA_HI_PAGE_5);
                break;
        case 6:
-               if (SND_DMA1 == 6 || SND_DMA2 == 6)
-                       dma_outb(pagenr, DMA_LO_PAGE_6);
-               else
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
                dma_outb(pagenr >> 8, DMA_HI_PAGE_6);
                break;
        case 7:
-               if (SND_DMA1 == 7 || SND_DMA2 == 7)
-                       dma_outb(pagenr, DMA_LO_PAGE_7);
-               else
-                       dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+               dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
                dma_outb(pagenr >> 8, DMA_HI_PAGE_7);
                break;
        }
@@ -302,12 +283,6 @@ static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys)
                         ((dmanr & 3) << 1) + IO_DMA1_BASE);
                dma_outb((phys >> 8) & 0xff,
                         ((dmanr & 3) << 1) + IO_DMA1_BASE);
-       } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-               dma_outb(phys & 0xff,
-                        ((dmanr & 3) << 2) + IO_DMA2_BASE);
-               dma_outb((phys >> 8) & 0xff,
-                        ((dmanr & 3) << 2) + IO_DMA2_BASE);
-               dma_outb((dmanr & 3), DMA2_EXT_REG);
        } else {
                dma_outb((phys >> 1) & 0xff,
                         ((dmanr & 3) << 2) + IO_DMA2_BASE);
@@ -334,11 +309,6 @@ static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
                         ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
                dma_outb((count >> 8) & 0xff,
                         ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
-       } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-               dma_outb(count & 0xff,
-                        ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
-               dma_outb((count >> 8) & 0xff,
-                        ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
        } else {
                dma_outb((count >> 1) & 0xff,
                         ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
@@ -368,8 +338,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
        count = 1 + dma_inb(io_port);
        count += dma_inb(io_port) << 8;
 
-       return (dmanr <= 3 || dmanr == SND_DMA1 || dmanr == SND_DMA2)
-           ? count : (count << 1);
+       return (dmanr <= 3) ? count : (count << 1);
 }
 
 /* These are in kernel/dma.c: */
index f6dfce0..748b35a 100644 (file)
@@ -115,8 +115,6 @@ struct paca_struct {
        u64 system_time;                /* accumulated system TB ticks */
        u64 startpurr;                  /* PURR/TB value snapshot */
        u64 startspurr;                 /* SPURR value snapshot */
-       u64 purrdelta;                  /* FIXME: document */
-       u64 spurrdelta;                 /* FIXME: document */
 };
 
 extern struct paca_struct paca[];
index 967930b..fda9871 100644 (file)
 #define PS3AV_MONITOR_TYPE_HDMI                        1       /* HDMI */
 #define PS3AV_MONITOR_TYPE_DVI                 2       /* DVI */
 
-#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60      2       /* 480p */
-#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60   1       /* 480i */
-#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50      7       /* 576p */
-#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50   6       /* 576i */
-
-#define PS3AV_REGION_60                                0x01
-#define PS3AV_REGION_50                                0x02
-#define PS3AV_REGION_RGB                       0x10
-
-#define get_status(buf)                                (((__u32 *)buf)[2])
-#define PS3AV_HDR_SIZE                         4       /* version + size */
 
 /* for video mode */
+enum ps3av_mode_num {
+       PS3AV_MODE_AUTO                         = 0,
+       PS3AV_MODE_480I                         = 1,
+       PS3AV_MODE_480P                         = 2,
+       PS3AV_MODE_720P60                       = 3,
+       PS3AV_MODE_1080I60                      = 4,
+       PS3AV_MODE_1080P60                      = 5,
+       PS3AV_MODE_576I                         = 6,
+       PS3AV_MODE_576P                         = 7,
+       PS3AV_MODE_720P50                       = 8,
+       PS3AV_MODE_1080I50                      = 9,
+       PS3AV_MODE_1080P50                      = 10,
+       PS3AV_MODE_WXGA                         = 11,
+       PS3AV_MODE_SXGA                         = 12,
+       PS3AV_MODE_WUXGA                        = 13,
+};
+
 #define PS3AV_MODE_MASK                                0x000F
 #define PS3AV_MODE_HDCP_OFF                    0x1000  /* Retail PS3 product doesn't support this */
 #define PS3AV_MODE_DITHER                      0x0800
 #define PS3AV_MODE_RGB                         0x0020
 
 
+#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60      PS3AV_MODE_480P
+#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60   PS3AV_MODE_480I
+#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50      PS3AV_MODE_576P
+#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50   PS3AV_MODE_576I
+
+#define PS3AV_REGION_60                                0x01
+#define PS3AV_REGION_50                                0x02
+#define PS3AV_REGION_RGB                       0x10
+
+#define get_status(buf)                                (((__u32 *)buf)[2])
+#define PS3AV_HDR_SIZE                         4       /* version + size */
+
+
 /** command packet structure **/
 struct ps3av_send_hdr {
        u16 version;
@@ -713,8 +732,6 @@ extern int ps3av_set_video_mode(u32);
 extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
 extern int ps3av_get_auto_mode(void);
 extern int ps3av_get_mode(void);
-extern int ps3av_get_scanmode(int);
-extern int ps3av_get_refresh_rate(int);
 extern int ps3av_video_mode2res(u32, u32 *, u32 *);
 extern int ps3av_video_mute(int);
 extern int ps3av_audio_mute(int);
index 4b3ef7c..133ce05 100644 (file)
@@ -54,6 +54,7 @@ __div(unsigned long long n, unsigned int base)
 #define cputime_lt(__a, __b)           ((__a) <  (__b))
 #define cputime_le(__a, __b)           ((__a) <= (__b))
 #define cputime_to_jiffies(__ct)       (__div((__ct), 1000000 / HZ))
+#define cputime_to_scaled(__ct)                (__ct)
 #define jiffies_to_cputime(__hz)       ((cputime_t)(__hz) * (1000000 / HZ))
 
 #define cputime64_zero                 (0ULL)
index 031db84..d5d4640 100644 (file)
@@ -12,7 +12,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 #ifdef CONFIG_SUPERH32
index 0decdf7..2338a02 100644 (file)
 #define __NR_epoll_pwait       309
 #define __NR_utimensat         310
 #define __NR_signalfd          311
-#define __NR_timerfd           312
+#define __NR_timerfd_create    312
 #define __NR_eventfd           313
 #define __NR_fallocate         314
+#define __NR_timerfd_settime   315
+#define __NR_timerfd_gettime   316
 
-#define NR_SYSCALLS            315
+#define NR_SYSCALLS            317
 
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
  * it never had the plain ones and there is no value to adding those
index c299b85..b6ece22 100644 (file)
@@ -16,7 +16,7 @@
 /* BIO layer definitions. */
 extern unsigned long kern_base, kern_size;
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
-#define BIO_VMERGE_BOUNDARY    8192
+#define BIO_VMERGE_BOUNDARY    0
 
 static inline u8 _inb(unsigned long addr)
 {
index 2a5e4eb..c622535 100644 (file)
 typedef unsigned long cycles_t;
 #define get_cycles()   tick_ops->get_tick()
 
-#define ARCH_HAS_READ_CURRENT_TIMER    1
-#define read_current_timer(timer_val_p)        \
-({     *timer_val_p = tick_ops->get_tick();    \
-       0;                                      \
-})
+#define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif
index cb751b4..77559da 100644 (file)
 #define __NR_epoll_pwait       309
 #define __NR_utimensat         310
 #define __NR_signalfd          311
-#define __NR_timerfd           312
+#define __NR_timerfd_create    312
 #define __NR_eventfd           313
 #define __NR_fallocate         314
+#define __NR_timerfd_settime   315
+#define __NR_timerfd_gettime   316
 
-#define NR_SYSCALLS            315
+#define NR_SYSCALLS            317
 
 #ifdef __KERNEL__
 /* sysconf options, for SunOS compatibility */
index cc364fc..cdad251 100644 (file)
@@ -122,8 +122,6 @@ outsl (unsigned long port, const void *src, unsigned long count)
 #endif
 
 /* Conversion between virtual and physical mappings.  */
-#define mm_ptov(addr)          ((void *)__phys_to_virt (addr))
-#define mm_vtop(addr)          ((unsigned long)__virt_to_phys (addr))
 #define phys_to_virt(addr)     ((void *)__phys_to_virt (addr))
 #define virt_to_phys(addr)     ((unsigned long)__virt_to_phys (addr))
 
index d11d47f..409a649 100644 (file)
@@ -13,7 +13,7 @@ extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
 extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
+extern void __const_udelay(unsigned long xloops);
 extern void __delay(unsigned long loops);
 
 /* 0x10c7 is 2**32 / 1000000 (rounded up) */
index 27cfd6c..43e5a78 100644 (file)
@@ -14,7 +14,6 @@
 #endif
 #define CLOCK_TICK_RATE        PIT_TICK_RATE
 
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER    1
+#define ARCH_HAS_READ_CURRENT_TIMER
 
 #endif
index 22eb936..0260c3e 100644 (file)
@@ -326,11 +326,7 @@ struct ac97_ops
 #define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */
 };
 
-extern int ac97_read_proc (char *page_out, char **start, off_t off,
-                          int count, int *eof, void *data);
 extern int ac97_probe_codec(struct ac97_codec *);
-extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
-extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
 
 extern struct ac97_codec *ac97_alloc_codec(void);
 extern void ac97_release_codec(struct ac97_codec *codec);
@@ -363,7 +359,4 @@ struct ac97_quirk {
        int type;               /* quirk type above */
 };
 
-struct pci_dev;
-extern int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override);
-
 #endif /* _AC97_CODEC_H_ */
index 302eb72..e8cae54 100644 (file)
@@ -173,7 +173,11 @@ typedef struct acct acct_t;
 static inline u32 jiffies_to_AHZ(unsigned long x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / AHZ)) == 0
+# if HZ < AHZ
+       return x * (AHZ / HZ);
+# else
        return x / (HZ / AHZ);
+# endif
 #else
         u64 tmp = (u64)x * TICK_NSEC;
         do_div(tmp, (NSEC_PER_SEC / AHZ));
index bdca3f1..eb640f0 100644 (file)
@@ -47,7 +47,6 @@ struct dma_chan_ref {
  * address is an implied source, whereas the asynchronous case it must be listed
  * as a source.  The destination address must be the first address in the source
  * array.
- * @ASYNC_TX_ASSUME_COHERENT: skip cache maintenance operations
  * @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
  * dependency chain
  * @ASYNC_TX_DEP_ACK: ack the dependency descriptor.  Useful for chaining.
@@ -55,7 +54,6 @@ struct dma_chan_ref {
 enum async_tx_flags {
        ASYNC_TX_XOR_ZERO_DST    = (1 << 0),
        ASYNC_TX_XOR_DROP_DST    = (1 << 1),
-       ASYNC_TX_ASSUME_COHERENT = (1 << 2),
        ASYNC_TX_ACK             = (1 << 3),
        ASYNC_TX_DEP_ACK         = (1 << 4),
 };
@@ -64,9 +62,15 @@ enum async_tx_flags {
 void async_tx_issue_pending_all(void);
 enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
 void async_tx_run_dependencies(struct dma_async_tx_descriptor *tx);
+#ifdef CONFIG_ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+#include <asm/async_tx.h>
+#else
+#define async_tx_find_channel(dep, type, dst, dst_count, src, src_count, len) \
+        __async_tx_find_channel(dep, type)
 struct dma_chan *
-async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+__async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
        enum dma_transaction_type tx_type);
+#endif /* CONFIG_ARCH_HAS_ASYNC_TX_FIND_CHANNEL */
 #else
 static inline void async_tx_issue_pending_all(void)
 {
@@ -88,7 +92,8 @@ async_tx_run_dependencies(struct dma_async_tx_descriptor *tx,
 
 static inline struct dma_chan *
 async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
-       enum dma_transaction_type tx_type)
+       enum dma_transaction_type tx_type, struct page **dst, int dst_count,
+       struct page **src, int src_count, size_t len)
 {
        return NULL;
 }
diff --git a/include/linux/ata_platform.h b/include/linux/ata_platform.h
new file mode 100644 (file)
index 0000000..b856a2a
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __LINUX_ATA_PLATFORM_H
+#define __LINUX_ATA_PLATFORM_H
+
+struct pata_platform_info {
+       /*
+        * I/O port shift, for platforms with ports that are
+        * constantly spaced and need larger than the 1-byte
+        * spacing used by ata_std_ports().
+        */
+       unsigned int ioport_shift;
+       /* 
+        * Indicate platform specific irq types and initial
+        * IRQ flags when call request_irq()
+        */
+       unsigned int irq_flags;
+};
+
+extern int __devinit __pata_platform_probe(struct device *dev,
+                                          struct resource *io_res,
+                                          struct resource *ctl_res,
+                                          struct resource *irq_res,
+                                          unsigned int ioport_shift,
+                                          int __pio_mask);
+
+extern int __devexit __pata_platform_remove(struct device *dev);
+
+/*
+ * Marvell SATA private data
+ */
+struct mv_sata_platform_data {
+       int     n_ports; /* number of sata ports */
+};
+
+#endif /* __LINUX_ATA_PLATFORM_H */
index ae0a483..a671dbf 100644 (file)
@@ -257,16 +257,8 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
 /*
  * epoll (fs/eventpoll.c) compat bits follow ...
  */
-#ifndef CONFIG_HAS_COMPAT_EPOLL_EVENT
 struct epoll_event;
 #define compat_epoll_event     epoll_event
-#else
-asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd,
-                       struct compat_epoll_event __user *event);
-asmlinkage long compat_sys_epoll_wait(int epfd,
-                       struct compat_epoll_event __user *events,
-                       int maxevents, int timeout);
-#endif
 asmlinkage long compat_sys_epoll_pwait(int epfd,
                        struct compat_epoll_event __user *events,
                        int maxevents, int timeout,
index 5c84bf8..acbb364 100644 (file)
@@ -94,6 +94,15 @@ enum dma_transaction_type {
 /* last transaction type for creation of the capabilities mask */
 #define DMA_TX_TYPE_END (DMA_INTERRUPT + 1)
 
+/**
+ * enum dma_prep_flags - DMA flags to augment operation preparation
+ * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of
+ *     this transaction
+ */
+enum dma_prep_flags {
+       DMA_PREP_INTERRUPT = (1 << 0),
+};
+
 /**
  * dma_cap_mask_t - capabilities bitmap modeled after cpumask_t.
  * See linux/cpumask.h
@@ -209,8 +218,6 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param);
  *     descriptors
  * @chan: target channel for this operation
  * @tx_submit: set the prepared descriptor(s) to be executed by the engine
- * @tx_set_dest: set a destination address in a hardware descriptor
- * @tx_set_src: set a source address in a hardware descriptor
  * @callback: routine to call after this operation is complete
  * @callback_param: general parameter to pass to the callback routine
  * ---async_tx api specific fields---
@@ -227,10 +234,6 @@ struct dma_async_tx_descriptor {
        struct list_head tx_list;
        struct dma_chan *chan;
        dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
-       void (*tx_set_dest)(dma_addr_t addr,
-               struct dma_async_tx_descriptor *tx, int index);
-       void (*tx_set_src)(dma_addr_t addr,
-               struct dma_async_tx_descriptor *tx, int index);
        dma_async_tx_callback callback;
        void *callback_param;
        struct list_head depend_list;
@@ -279,15 +282,17 @@ struct dma_device {
        void (*device_free_chan_resources)(struct dma_chan *chan);
 
        struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
-               struct dma_chan *chan, size_t len, int int_en);
+               struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+               size_t len, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
-               struct dma_chan *chan, unsigned int src_cnt, size_t len,
-               int int_en);
+               struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
+               unsigned int src_cnt, size_t len, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_zero_sum)(
-               struct dma_chan *chan, unsigned int src_cnt, size_t len,
-               u32 *result, int int_en);
+               struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt,
+               size_t len, u32 *result, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_memset)(
-               struct dma_chan *chan, int value, size_t len, int int_en);
+               struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
+               unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
                struct dma_chan *chan);
 
index 56bd421..109734b 100644 (file)
@@ -21,7 +21,7 @@
 
 /* Fixed constants first: */
 #undef NR_OPEN
-#define NR_OPEN (1024*1024)    /* Absolute upper limit on fd num */
+extern int sysctl_nr_open;
 #define INR_OPEN 1024          /* Initial setting for nfile rlimits */
 
 #define BLOCK_SIZE_BITS 10
@@ -977,7 +977,6 @@ extern int send_sigurg(struct fown_struct *fown);
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
 
-#define sb_entry(list) list_entry((list), struct super_block, s_list)
 #define S_BIAS (1<<30)
 struct super_block {
        struct list_head        s_list;         /* Keep this first */
@@ -1279,8 +1278,10 @@ struct super_operations {
  *
  * Two bits are used for locking and completion notification, I_LOCK and I_SYNC.
  *
- * I_DIRTY_SYNC                Inode itself is dirty.
- * I_DIRTY_DATASYNC    Data-related inode changes pending
+ * I_DIRTY_SYNC                Inode is dirty, but doesn't have to be written on
+ *                     fdatasync().  i_atime is the usual cause.
+ * I_DIRTY_DATASYNC    Inode is dirty and must be written on fdatasync(), f.e.
+ *                     because i_size changed.
  * I_DIRTY_PAGES       Inode has dirty pages.  Inode itself may be clean.
  * I_NEW               get_new_inode() sets i_state to I_LOCK|I_NEW.  Both
  *                     are cleared by unlock_new_inode(), called from iget().
@@ -1312,8 +1313,6 @@ struct super_operations {
  *                     purpose reduces latency and prevents some filesystem-
  *                     specific deadlocks.
  *
- * Q: Why does I_DIRTY_DATASYNC exist?  It appears as if it could be replaced
- *    by (I_DIRTY_SYNC|I_DIRTY_PAGES).
  * Q: What is the difference between I_WILL_FREE and I_FREEING?
  * Q: igrab() only checks on (I_FREEING|I_WILL_FREE).  Should it also check on
  *    I_CLEAR?  If not, why?
@@ -2113,6 +2112,7 @@ struct ctl_table;
 int proc_nr_files(struct ctl_table *table, int write, struct file *filp,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
 
+int get_filesystem_list(char * buf);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */
index 2bd31fa..d4b7c4a 100644 (file)
@@ -91,6 +91,14 @@ static inline void fsnotify_inoderemove(struct inode *inode)
        inotify_inode_is_dead(inode);
 }
 
+/*
+ * fsnotify_link_count - inode's link count changed
+ */
+static inline void fsnotify_link_count(struct inode *inode)
+{
+       inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
+}
+
 /*
  * fsnotify_create - 'name' was linked in
  */
@@ -102,6 +110,20 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
        audit_inode_child(dentry->d_name.name, dentry, inode);
 }
 
+/*
+ * fsnotify_link - new hardlink in 'inode' directory
+ * Note: We have to pass also the linked inode ptr as some filesystems leave
+ *   new_dentry->d_inode NULL and instantiate inode pointer later
+ */
+static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
+{
+       inode_dir_notify(dir, DN_CREATE);
+       inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
+                                 inode);
+       fsnotify_link_count(inode);
+       audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
+}
+
 /*
  * fsnotify_mkdir - directory 'name' was created
  */
index acf17bb..06d25c1 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef _LINUX_HASH_H
 #define _LINUX_HASH_H
-/* Fast hashing routine for a long.
+/* Fast hashing routine for ints,  longs and pointers.
    (C) 2002 William Lee Irwin III, IBM */
 
 /*
  * them can use shifts and additions instead of multiplications for
  * machines where multiplications are slow.
  */
-#if BITS_PER_LONG == 32
+
+#include <asm/types.h>
+
 /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e370001UL
-#elif BITS_PER_LONG == 64
+#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
 /*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
+#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL
+
+#if BITS_PER_LONG == 32
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32
+#define hash_long(val, bits) hash_32(val, bits)
+#elif BITS_PER_LONG == 64
+#define hash_long(val, bits) hash_64(val, bits)
+#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64
 #else
-#error Define GOLDEN_RATIO_PRIME for your wordsize.
+#error Wordsize not 32 or 64
 #endif
 
-static inline unsigned long hash_long(unsigned long val, unsigned int bits)
+static inline u64 hash_64(u64 val, unsigned int bits)
 {
-       unsigned long hash = val;
+       u64 hash = val;
 
-#if BITS_PER_LONG == 64
        /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
-       unsigned long n = hash;
+       u64 n = hash;
        n <<= 18;
        hash -= n;
        n <<= 33;
@@ -42,15 +49,20 @@ static inline unsigned long hash_long(unsigned long val, unsigned int bits)
        hash += n;
        n <<= 2;
        hash += n;
-#else
+
+       /* High bits are more random, so use them. */
+       return hash >> (64 - bits);
+}
+
+static inline u32 hash_32(u32 val, unsigned int bits)
+{
        /* On some cpus multiply is faster, on others gcc will do shifts */
-       hash *= GOLDEN_RATIO_PRIME;
-#endif
+       u32 hash = val * GOLDEN_RATIO_PRIME_32;
 
        /* High bits are more random, so use them. */
-       return hash >> (BITS_PER_LONG - bits);
+       return hash >> (32 - bits);
 }
-       
+
 static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
 {
        return hash_long((unsigned long)ptr, bits);
index db390c5..6115545 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/hdlc/ioctl.h>
 
-
-/* Used by all network devices here, pointed to by netdev_priv(dev) */
-struct hdlc_device_desc {
-       int (*netif_rx)(struct sk_buff *skb);
-       struct net_device_stats stats;
-};
-
 /* This structure is a private property of HDLC protocols.
    Hardware drivers have no interest here */
 
@@ -44,12 +37,15 @@ struct hdlc_proto {
        void (*detach)(struct net_device *dev);
        int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
        __be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev);
+       int (*netif_rx)(struct sk_buff *skb);
        struct module *module;
        struct hdlc_proto *next; /* next protocol in the list */
 };
 
 
+/* Pointed to by dev->priv */
 typedef struct hdlc_device {
+       struct net_device_stats stats;
        /* used by HDLC layer to take control over HDLC device from hw driver*/
        int (*attach)(struct net_device *dev,
                      unsigned short encoding, unsigned short parity);
@@ -83,18 +79,11 @@ void unregister_hdlc_protocol(struct hdlc_proto *proto);
 
 struct net_device *alloc_hdlcdev(void *priv);
 
-
-static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev)
-{
-       return netdev_priv(dev);
-}
-
-static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+static inline struct hdlc_device* dev_to_hdlc(struct net_device *dev)
 {
-       return netdev_priv(dev) + sizeof(struct hdlc_device_desc);
+       return dev->priv;
 }
 
-
 static __inline__ void debug_frame(const struct sk_buff *skb)
 {
        int i;
@@ -116,13 +105,13 @@ int hdlc_open(struct net_device *dev);
 void hdlc_close(struct net_device *dev);
 
 int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
-                        int (*rx)(struct sk_buff *skb), size_t size);
+                        size_t size);
 /* May be used by hardware driver to gain control over HDLC device */
 void detach_hdlc_protocol(struct net_device *dev);
 
 static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
 {
-       return &dev_to_desc(dev)->stats;
+       return &dev_to_hdlc(dev)->stats;
 }
 
 
diff --git a/include/linux/i2c/pca9539.h b/include/linux/i2c/pca9539.h
deleted file mode 100644 (file)
index 611d84a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* platform data for the PCA9539 16-bit I/O expander driver */
-
-struct pca9539_platform_data {
-       /* number of the first GPIO */
-       unsigned        gpio_base;
-
-       /* initial polarity inversion setting */
-       uint16_t        invert;
-
-       void            *context;       /* param to setup/teardown */
-
-       int             (*setup)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-       int             (*teardown)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-};
diff --git a/include/linux/i2c/pca953x.h b/include/linux/i2c/pca953x.h
new file mode 100644 (file)
index 0000000..3c73612
--- /dev/null
@@ -0,0 +1,18 @@
+/* platform data for the PCA9539 16-bit I/O expander driver */
+
+struct pca953x_platform_data {
+       /* number of the first GPIO */
+       unsigned        gpio_base;
+
+       /* initial polarity inversion setting */
+       uint16_t        invert;
+
+       void            *context;       /* param to setup/teardown */
+
+       int             (*setup)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+       int             (*teardown)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+};
index 34f40ef..79504b2 100644 (file)
@@ -327,7 +327,7 @@ static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short t
  * 
  * Returns error if the skb is not of VLAN type
  */
-static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
 {
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
 
@@ -347,7 +347,8 @@ static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
  * 
  * Returns error if @skb->cb[] is not set correctly
  */
-static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
+                                        unsigned short *tag)
 {
        struct vlan_skb_tx_cookie *cookie;
 
@@ -370,7 +371,7 @@ static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *ta
  * 
  * Returns error if the skb is not VLAN tagged
  */
-static inline int vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
+static inline int vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
 {
        if (skb->dev->features & NETIF_F_HW_VLAN_TX) {
                return __vlan_hwaccel_get_tag(skb, tag);
index c3db4a0..dea7598 100644 (file)
@@ -444,4 +444,6 @@ static inline void init_irq_proc(void)
 }
 #endif
 
+int show_interrupts(struct seq_file *p, void *v);
+
 #endif
index d0ecc8e..9cb2855 100644 (file)
@@ -507,7 +507,6 @@ typedef struct modem_info {
   struct ktermios      normal_termios;  /* For saving termios structs     */
   struct ktermios      callout_termios;
   wait_queue_head_t    open_wait, close_wait;
-  struct semaphore      write_sem;
   spinlock_t           readlock;
 } modem_info;
 
index d9ecd13..b18fd3b 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/lockdep.h>
 
 #include <asm/semaphore.h>
-#endif
 
 #define journal_oom_retry 1
 
@@ -84,7 +83,6 @@ static inline void jbd_free(void *ptr, size_t size)
 
 #define JFS_MIN_JOURNAL_BLOCKS 1024
 
-#ifdef __KERNEL__
 
 /**
  * typedef handle_t - The handle_t type represents a single atomic update being performed by some process.
@@ -924,7 +922,6 @@ extern int     journal_recover    (journal_t *journal);
 extern int        journal_wipe       (journal_t *, int);
 extern int        journal_skip_recovery        (journal_t *);
 extern void       journal_update_superblock    (journal_t *, int);
-extern void       __journal_abort_hard (journal_t *);
 extern void       journal_abort      (journal_t *, int);
 extern int        journal_errno      (journal_t *);
 extern void       journal_ack_err    (journal_t *);
index ff356b2..18222f2 100644 (file)
@@ -35,7 +35,7 @@ extern const char linux_proc_banner[];
 #define ALIGN(x,a)             __ALIGN_MASK(x,(typeof(x))(a)-1)
 #define __ALIGN_MASK(x,mask)   (((x)+(mask))&~(mask))
 #define PTR_ALIGN(p, a)                ((typeof(p))ALIGN((unsigned long)(p), (a)))
-#define IS_ALIGNED(x,a)                (((x) % ((typeof(x))(a))) == 0)
+#define IS_ALIGNED(x, a)               (((x) & ((typeof(x))(a) - 1)) == 0)
 
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
 
index 6168c0a..4a6ce82 100644 (file)
@@ -152,8 +152,10 @@ static inline int arch_trampoline_kprobe(struct kprobe *p)
 struct kretprobe {
        struct kprobe kp;
        kretprobe_handler_t handler;
+       kretprobe_handler_t entry_handler;
        int maxactive;
        int nmissed;
+       size_t data_size;
        struct hlist_head free_instances;
        struct hlist_head used_instances;
 };
@@ -164,6 +166,7 @@ struct kretprobe_instance {
        struct kretprobe *rp;
        kprobe_opcode_t *ret_addr;
        struct task_struct *task;
+       char data[0];
 };
 
 struct kretprobe_blackpoint {
index 4374c42..bc5a8d0 100644 (file)
@@ -457,7 +457,6 @@ struct ata_queued_cmd {
        unsigned long           flags;          /* ATA_QCFLAG_xxx */
        unsigned int            tag;
        unsigned int            n_elem;
-       unsigned int            n_iter;
        unsigned int            mapped_n_elem;
 
        int                     dma_dir;
@@ -1367,7 +1366,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
        qc->nbytes = qc->raw_nbytes = qc->curbytes = 0;
        qc->n_elem = 0;
        qc->mapped_n_elem = 0;
-       qc->n_iter = 0;
        qc->err_mask = 0;
        qc->pad_len = 0;
        qc->last_sg = NULL;
index c8cf5e8..25b8086 100644 (file)
@@ -190,4 +190,20 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
        __rounddown_pow_of_two(n)               \
  )
 
+/**
+ * order_base_2 - calculate the (rounded up) base 2 order of the argument
+ * @n: parameter
+ *
+ * The first few values calculated by this routine:
+ *  ob2(0) = 0
+ *  ob2(1) = 0
+ *  ob2(2) = 1
+ *  ob2(3) = 2
+ *  ob2(4) = 2
+ *  ob2(5) = 3
+ *  ... and so on.
+ */
+
+#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+
 #endif /* _LINUX_LOG2_H */
index 26a0a10..46169a7 100644 (file)
@@ -76,6 +76,7 @@ struct loop_device {
 enum {
        LO_FLAGS_READ_ONLY      = 1,
        LO_FLAGS_USE_AOPS       = 2,
+       LO_FLAGS_AUTOCLEAR      = 4,
 };
 
 #include <asm/posix_types.h>   /* for __kernel_old_dev_t */
index 7059b6b..0df024b 100644 (file)
@@ -99,7 +99,7 @@
 #ifdef __KERNEL__
 
 #include <linux/wait.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /* Magic numbers for defining port-device mappings */
 #define LP_PARPORT_UNSPEC -4
@@ -145,7 +145,7 @@ struct lp_struct {
 #endif
        wait_queue_head_t waitq;
        unsigned int last_error;
-       struct semaphore port_mutex;
+       struct mutex port_mutex;
        wait_queue_head_t dataq;
        long timeout;
        unsigned int best_mode;
diff --git a/include/linux/pata_platform.h b/include/linux/pata_platform.h
deleted file mode 100644 (file)
index 6a7a92d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __LINUX_PATA_PLATFORM_H
-#define __LINUX_PATA_PLATFORM_H
-
-struct pata_platform_info {
-       /*
-        * I/O port shift, for platforms with ports that are
-        * constantly spaced and need larger than the 1-byte
-        * spacing used by ata_std_ports().
-        */
-       unsigned int ioport_shift;
-       /* 
-        * Indicate platform specific irq types and initial
-        * IRQ flags when call request_irq()
-        */
-       unsigned int irq_flags;
-};
-
-extern int __devinit __pata_platform_probe(struct device *dev,
-                                          struct resource *io_res,
-                                          struct resource *ctl_res,
-                                          struct resource *irq_res,
-                                          unsigned int ioport_shift,
-                                          int __pio_mask);
-
-extern int __devexit __pata_platform_remove(struct device *dev);
-
-#endif /* __LINUX_PATA_PLATFORM_H */
index 39d3283..df6dd79 100644 (file)
 #define PCI_DEVICE_ID_QUATECH_DSC100   0x0020
 #define PCI_DEVICE_ID_QUATECH_ESC100D  0x0050
 #define PCI_DEVICE_ID_QUATECH_ESC100M  0x0060
+#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278
 
 #define PCI_VENDOR_ID_SEALEVEL         0x135e
 #define PCI_DEVICE_ID_SEALEVEL_U530    0x7101
index 50faa0e..1ac9697 100644 (file)
@@ -54,7 +54,7 @@
 #ifdef CONFIG_SMP
 
 struct percpu_data {
-       void *ptrs[NR_CPUS];
+       void *ptrs[1];
 };
 
 #define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata)
index 40fac8c..28dfc61 100644 (file)
@@ -348,6 +348,7 @@ enum
        FLOW_KEY_RTCLASSID,
        FLOW_KEY_SKUID,
        FLOW_KEY_SKGID,
+       FLOW_KEY_VLAN_TAG,
        __FLOW_KEY_MAX,
 };
 
index b9339d8..cd6332b 100644 (file)
@@ -258,6 +258,7 @@ extern struct pnp_protocol isapnp_protocol;
 #else
 #define pnp_device_is_isapnp(dev) 0
 #endif
+extern struct mutex pnp_res_mutex;
 
 #ifdef CONFIG_PNPBIOS
 extern struct pnp_protocol pnpbios_protocol;
index 515bff0..6ab8071 100644 (file)
@@ -204,6 +204,41 @@ static inline void user_enable_block_step(struct task_struct *task)
 }
 #endif /* arch_has_block_step */
 
+#ifndef arch_ptrace_stop_needed
+/**
+ * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called
+ * @code:      current->exit_code value ptrace will stop with
+ * @info:      siginfo_t pointer (or %NULL) for signal ptrace will stop with
+ *
+ * This is called with the siglock held, to decide whether or not it's
+ * necessary to release the siglock and call arch_ptrace_stop() with the
+ * same @code and @info arguments.  It can be defined to a constant if
+ * arch_ptrace_stop() is never required, or always is.  On machines where
+ * this makes sense, it should be defined to a quick test to optimize out
+ * calling arch_ptrace_stop() when it would be superfluous.  For example,
+ * if the thread has not been back to user mode since the last stop, the
+ * thread state might indicate that nothing needs to be done.
+ */
+#define arch_ptrace_stop_needed(code, info)    (0)
+#endif
+
+#ifndef arch_ptrace_stop
+/**
+ * arch_ptrace_stop - Do machine-specific work before stopping for ptrace
+ * @code:      current->exit_code value ptrace will stop with
+ * @info:      siginfo_t pointer (or %NULL) for signal ptrace will stop with
+ *
+ * This is called with no locks held when arch_ptrace_stop_needed() has
+ * just returned nonzero.  It is allowed to block, e.g. for user memory
+ * access.  The arch can have machine-specific work to be done before
+ * ptrace stops.  On ia64, register backing store gets written back to user
+ * memory here.  Since this can be costly (requires dropping the siglock),
+ * we only do it when the arch requires it for this particular stop, as
+ * indicated by arch_ptrace_stop_needed().
+ */
+#define arch_ptrace_stop(code, info)           do { } while (0)
+#endif
+
 #endif
 
 #endif
index 306a1d1..e51b531 100644 (file)
@@ -244,6 +244,8 @@ struct bitmap {
         */
        unsigned long daemon_lastrun; /* jiffies of last run */
        unsigned long daemon_sleep; /* how many seconds between updates? */
+       unsigned long last_end_sync; /* when we lasted called end_sync to
+                                     * update bitmap with resync progress */
 
        atomic_t pending_writes; /* pending writes to the bitmap file */
        wait_queue_head_t write_wait;
@@ -275,6 +277,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset,
 int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded);
 void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted);
 void bitmap_close_sync(struct bitmap *bitmap);
+void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);
 
 void bitmap_unplug(struct bitmap *bitmap);
 void bitmap_daemon_work(struct bitmap *bitmap);
index dcb7292..85a068b 100644 (file)
@@ -81,6 +81,8 @@ struct mdk_rdev_s
 #define        In_sync         2               /* device is in_sync with rest of array */
 #define        WriteMostly     4               /* Avoid reading if at all possible */
 #define        BarriersNotsupp 5               /* BIO_RW_BARRIER is not supported */
+#define        AllReserved     6               /* If whole device is reserved for
+                                        * one array */
 
        int desc_nr;                    /* descriptor index in the superblock */
        int raid_disk;                  /* role of device in array */
@@ -130,6 +132,9 @@ struct mddev_s
                                        minor_version,
                                        patch_version;
        int                             persistent;
+       int                             external;       /* metadata is
+                                                        * managed externally */
+       char                            metadata_type[17]; /* externally set*/
        int                             chunk_size;
        time_t                          ctime, utime;
        int                             level, layout;
@@ -216,6 +221,8 @@ struct mddev_s
        atomic_t                        recovery_active; /* blocks scheduled, but not written */
        wait_queue_head_t               recovery_wait;
        sector_t                        recovery_cp;
+       sector_t                        resync_max;     /* resync should pause
+                                                        * when it gets here */
 
        spinlock_t                      write_lock;
        wait_queue_head_t               sb_wait;        /* for waiting on superblock updates */
@@ -306,23 +313,17 @@ static inline char * mdname (mddev_t * mddev)
  * iterates through some rdev ringlist. It's safe to remove the
  * current 'rdev'. Dont touch 'tmp' though.
  */
-#define ITERATE_RDEV_GENERIC(head,rdev,tmp)                            \
+#define rdev_for_each_list(rdev, tmp, list)                            \
                                                                        \
-       for ((tmp) = (head).next;                                       \
+       for ((tmp) = (list).next;                                       \
                (rdev) = (list_entry((tmp), mdk_rdev_t, same_set)),     \
-                       (tmp) = (tmp)->next, (tmp)->prev != &(head)     \
+                       (tmp) = (tmp)->next, (tmp)->prev != &(list)     \
                ; )
 /*
  * iterates through the 'same array disks' ringlist
  */
-#define ITERATE_RDEV(mddev,rdev,tmp)                                   \
-       ITERATE_RDEV_GENERIC((mddev)->disks,rdev,tmp)
-
-/*
- * Iterates through 'pending RAID disks'
- */
-#define ITERATE_RDEV_PENDING(rdev,tmp)                                 \
-       ITERATE_RDEV_GENERIC(pending_raid_disks,rdev,tmp)
+#define rdev_for_each(rdev, tmp, mddev)                                \
+       rdev_for_each_list(rdev, tmp, (mddev)->disks)
 
 typedef struct mdk_thread_s {
        void                    (*run) (mddev_t *mddev);
index d32c14d..37a642c 100644 (file)
@@ -174,10 +174,13 @@ struct rcu_head {
  * code.
  */
 
-#define rcu_assign_pointer(p, v)       ({ \
-                                               smp_wmb(); \
-                                               (p) = (v); \
-                                       })
+#define rcu_assign_pointer(p, v) \
+       ({ \
+               if (!__builtin_constant_p(v) || \
+                   ((v) != NULL)) \
+                       smp_wmb(); \
+               (p) = (v); \
+       })
 
 /**
  * synchronize_sched - block until all CPUs have exited any non-preemptive
index 9c13be3..7c8ca05 100644 (file)
@@ -810,7 +810,7 @@ static inline int above_background_load(void)
 
 struct io_context;                     /* See blkdev.h */
 #define NGROUPS_SMALL          32
-#define NGROUPS_PER_BLOCK      ((int)(PAGE_SIZE / sizeof(gid_t)))
+#define NGROUPS_PER_BLOCK      ((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
 struct group_info {
        int ngroups;
        atomic_t usage;
index 0ae3388..7e09514 100644 (file)
@@ -371,6 +371,8 @@ int unhandled_signal(struct task_struct *tsk, int sig);
        (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
         (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
 
+void signals_init(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
index 9e3aaad..932a9ef 100644 (file)
@@ -70,6 +70,8 @@ extern unsigned long sm501_gpio_get(struct device *dev,
 #define SM501FB_FLAG_DISABLE_AT_EXIT   (1<<1)
 #define SM501FB_FLAG_USE_HWCURSOR      (1<<2)
 #define SM501FB_FLAG_USE_HWACCEL       (1<<3)
+#define SM501FB_FLAG_PANEL_USE_FPEN    (1<<4)
+#define SM501FB_FLAG_PANEL_USE_VBIASEN (1<<5)
 
 struct sm501_platdata_fbsub {
        struct fb_videomode     *def_mode;
index e18f5c2..9d5da8b 100644 (file)
@@ -373,6 +373,15 @@ void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state)
        if (sdev->bus->bustype == SSB_BUSTYPE_PCI)
                pci_set_power_state(sdev->bus->host_pci, state);
 }
+#else
+static inline void ssb_pcihost_unregister(struct pci_driver *driver)
+{
+}
+
+static inline
+void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state)
+{
+}
 #endif /* CONFIG_SSB_PCIHOST */
 
 
index 24c6a2b..8ea3e71 100644 (file)
@@ -244,6 +244,8 @@ extern int do_adjtimex(struct timex *);
 /* Don't use! Compatibility define for existing users. */
 #define tickadj        (500/HZ ? : 1)
 
+int read_current_timer(unsigned long *timer_val);
+
 #endif /* KERNEL */
 
 #endif /* LINUX_TIMEX_H */
index 402de89..5824a97 100644 (file)
@@ -74,7 +74,6 @@ struct tty_buffer {
 
 struct tty_bufhead {
        struct delayed_work work;
-       struct semaphore pty_sem;
        spinlock_t lock;
        struct tty_buffer *head;        /* Queue head */
        struct tty_buffer *tail;        /* Active buffer */
index feb5e99..9448ffb 100644 (file)
@@ -77,6 +77,7 @@ void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
 extern int unbind_con_driver(const struct consw *csw, int first, int last,
                             int deflt);
+int vty_init(void);
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
new file mode 100644 (file)
index 0000000..9797fec
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * w1-gpio interface to platform code
+ *
+ * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+#ifndef _LINUX_W1_GPIO_H
+#define _LINUX_W1_GPIO_H
+
+/**
+ * struct w1_gpio_platform_data - Platform-dependent data for w1-gpio
+ * @pin: GPIO pin to use
+ * @is_open_drain: GPIO pin is configured as open drain
+ */
+struct w1_gpio_platform_data {
+       unsigned int pin;
+       unsigned int is_open_drain:1;
+};
+
+#endif /* _LINUX_W1_GPIO_H */
index 4eea637..336c20d 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __ATMEL_LCDC_H__
 #define __ATMEL_LCDC_H__
 
- /* LCD Controller info data structure */
+ /* LCD Controller info data structure, stored in device platform_data */
 struct atmel_lcdfb_info {
        spinlock_t              lock;
        struct fb_info          *info;
@@ -33,7 +33,14 @@ struct atmel_lcdfb_info {
        struct platform_device  *pdev;
        struct clk              *bus_clk;
        struct clk              *lcdc_clk;
-       unsigned int            default_bpp;
+
+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+       struct backlight_device *backlight;
+       u8                      bl_power;
+#endif
+       bool                    lcdcon_is_backlight;
+
+       u8                      default_bpp;
        unsigned int            default_lcdcon2;
        unsigned int            default_dmacon;
        void (*atmel_lcdfb_power_control)(int on);
@@ -115,20 +122,20 @@ struct atmel_lcdfb_info {
 #define                ATMEL_LCDC_MEMOR_LITTLE         (1 << 31)
 
 #define ATMEL_LCDC_TIM1                0x0808
-#define        ATMEL_LCDC_VFP          (0xff <<  0)
+#define        ATMEL_LCDC_VFP          (0xffU <<  0)
 #define        ATMEL_LCDC_VBP_OFFSET           8
-#define        ATMEL_LCDC_VBP          (0xff <<  ATMEL_LCDC_VBP_OFFSET)
+#define        ATMEL_LCDC_VBP          (0xffU <<  ATMEL_LCDC_VBP_OFFSET)
 #define        ATMEL_LCDC_VPW_OFFSET           16
-#define        ATMEL_LCDC_VPW          (0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define        ATMEL_LCDC_VPW          (0x3fU << ATMEL_LCDC_VPW_OFFSET)
 #define        ATMEL_LCDC_VHDLY_OFFSET         24
-#define        ATMEL_LCDC_VHDLY        (0xf  << ATMEL_LCDC_VHDLY_OFFSET)
+#define        ATMEL_LCDC_VHDLY        (0xfU  << ATMEL_LCDC_VHDLY_OFFSET)
 
 #define ATMEL_LCDC_TIM2                0x080c
-#define        ATMEL_LCDC_HBP          (0xff  <<  0)
+#define        ATMEL_LCDC_HBP          (0xffU  <<  0)
 #define        ATMEL_LCDC_HPW_OFFSET           8
-#define        ATMEL_LCDC_HPW          (0x3f  <<  ATMEL_LCDC_HPW_OFFSET)
+#define        ATMEL_LCDC_HPW          (0x3fU  <<  ATMEL_LCDC_HPW_OFFSET)
 #define        ATMEL_LCDC_HFP_OFFSET           21
-#define        ATMEL_LCDC_HFP          (0x7ff << ATMEL_LCDC_HFP_OFFSET)
+#define        ATMEL_LCDC_HFP          (0x7ffU << ATMEL_LCDC_HFP_OFFSET)
 
 #define ATMEL_LCDC_LCDFRMCFG   0x0810
 #define        ATMEL_LCDC_LINEVAL      (0x7ff <<  0)
index 2d3d73b..ecb3822 100644 (file)
@@ -7,8 +7,7 @@
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-
-#include <asm/timex.h>
+#include <linux/timex.h>
 
 unsigned long preset_lpj;
 static int __init lpj_setup(char *str)
@@ -29,7 +28,7 @@ __setup("lpj=", lpj_setup);
 #define DELAY_CALIBRATION_TICKS                        ((HZ < 100) ? 1 : (HZ/100))
 #define MAX_DIRECT_CALIBRATION_RETRIES         5
 
-static unsigned long __devinit calibrate_delay_direct(void)
+static unsigned long __cpuinit calibrate_delay_direct(void)
 {
        unsigned long pre_start, start, post_start;
        unsigned long pre_end, end, post_end;
@@ -102,7 +101,7 @@ static unsigned long __devinit calibrate_delay_direct(void)
        return 0;
 }
 #else
-static unsigned long __devinit calibrate_delay_direct(void) {return 0;}
+static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
 #endif
 
 /*
@@ -112,7 +111,7 @@ static unsigned long __devinit calibrate_delay_direct(void) {return 0;}
  */
 #define LPS_PREC 8
 
-void __devinit calibrate_delay(void)
+void __cpuinit calibrate_delay(void)
 {
        unsigned long ticks, loopbit;
        int lps_precision = LPS_PREC;
index 1161dfd..f865731 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mount.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/fs.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
@@ -18,8 +19,6 @@
 
 #include "do_mounts.h"
 
-extern int get_filesystem_list(char * buf);
-
 int __initdata rd_doload;      /* 1 = load RAM disk, 0 = don't load */
 
 int root_mountflags = MS_RDONLY | MS_SILENT;
index 1db02a0..d53fee8 100644 (file)
@@ -503,7 +503,6 @@ static int __init retain_initrd_param(char *str)
 __setup("retain_initrd", retain_initrd_param);
 
 extern char __initramfs_start[], __initramfs_end[];
-#ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/initrd.h>
 #include <linux/kexec.h>
 
@@ -539,15 +538,12 @@ skip:
        initrd_end = 0;
 }
 
-#endif
-
 static int __init populate_rootfs(void)
 {
        char *err = unpack_to_rootfs(__initramfs_start,
                         __initramfs_end - __initramfs_start, 0);
        if (err)
                panic(err);
-#ifdef CONFIG_BLK_DEV_INITRD
        if (initrd_start) {
 #ifdef CONFIG_BLK_DEV_RAM
                int fd;
@@ -579,7 +575,6 @@ static int __init populate_rootfs(void)
                free_initrd();
 #endif
        }
-#endif
        return 0;
 }
 rootfs_initcall(populate_rootfs);
index cb81ed1..c691f5f 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/device.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>
+#include <linux/signal.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -83,7 +84,6 @@ extern void init_IRQ(void);
 extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
-extern void signals_init(void);
 extern void pidhash_init(void);
 extern void pidmap_init(void);
 extern void prio_tree_init(void);
index fdf3db5..ec0c724 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -105,6 +105,7 @@ int msg_init_ns(struct ipc_namespace *ns)
 void msg_exit_ns(struct ipc_namespace *ns)
 {
        struct msg_queue *msq;
+       struct kern_ipc_perm *perm;
        int next_id;
        int total, in_use;
 
@@ -113,10 +114,11 @@ void msg_exit_ns(struct ipc_namespace *ns)
        in_use = msg_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
-               msq = idr_find(&msg_ids(ns).ipcs_idr, next_id);
-               if (msq == NULL)
+               perm = idr_find(&msg_ids(ns).ipcs_idr, next_id);
+               if (perm == NULL)
                        continue;
-               ipc_lock_by_ptr(&msq->q_perm);
+               ipc_lock_by_ptr(perm);
+               msq = container_of(perm, struct msg_queue, q_perm);
                freeque(ns, msq);
                total++;
        }
@@ -144,6 +146,9 @@ static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct msg_queue *)ipcp;
+
        return container_of(ipcp, struct msg_queue, q_perm);
 }
 
@@ -155,6 +160,9 @@ static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id)
 {
        struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct msg_queue *)ipcp;
+
        return container_of(ipcp, struct msg_queue, q_perm);
 }
 
@@ -163,6 +171,9 @@ static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct msg_queue *)ipcp;
+
        return container_of(ipcp, struct msg_queue, q_perm);
 }
 
index 35952c0..d65e285 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -143,6 +143,7 @@ int sem_init_ns(struct ipc_namespace *ns)
 void sem_exit_ns(struct ipc_namespace *ns)
 {
        struct sem_array *sma;
+       struct kern_ipc_perm *perm;
        int next_id;
        int total, in_use;
 
@@ -151,10 +152,11 @@ void sem_exit_ns(struct ipc_namespace *ns)
        in_use = sem_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
-               sma = idr_find(&sem_ids(ns).ipcs_idr, next_id);
-               if (sma == NULL)
+               perm = idr_find(&sem_ids(ns).ipcs_idr, next_id);
+               if (perm == NULL)
                        continue;
-               ipc_lock_by_ptr(&sma->sem_perm);
+               ipc_lock_by_ptr(perm);
+               sma = container_of(perm, struct sem_array, sem_perm);
                freeary(ns, sma);
                total++;
        }
@@ -181,6 +183,9 @@ static inline struct sem_array *sem_lock_check_down(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct sem_array *)ipcp;
+
        return container_of(ipcp, struct sem_array, sem_perm);
 }
 
@@ -192,6 +197,9 @@ static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
 {
        struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct sem_array *)ipcp;
+
        return container_of(ipcp, struct sem_array, sem_perm);
 }
 
@@ -200,6 +208,9 @@ static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct sem_array *)ipcp;
+
        return container_of(ipcp, struct sem_array, sem_perm);
 }
 
index 3818fae..65c3a29 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -111,6 +111,7 @@ int shm_init_ns(struct ipc_namespace *ns)
 void shm_exit_ns(struct ipc_namespace *ns)
 {
        struct shmid_kernel *shp;
+       struct kern_ipc_perm *perm;
        int next_id;
        int total, in_use;
 
@@ -119,10 +120,11 @@ void shm_exit_ns(struct ipc_namespace *ns)
        in_use = shm_ids(ns).in_use;
 
        for (total = 0, next_id = 0; total < in_use; next_id++) {
-               shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
-               if (shp == NULL)
+               perm = idr_find(&shm_ids(ns).ipcs_idr, next_id);
+               if (perm == NULL)
                        continue;
-               ipc_lock_by_ptr(&shp->shm_perm);
+               ipc_lock_by_ptr(perm);
+               shp = container_of(perm, struct shmid_kernel, shm_perm);
                do_shm_rmid(ns, shp);
                total++;
        }
@@ -149,6 +151,9 @@ static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -158,6 +163,9 @@ static inline struct shmid_kernel *shm_lock_check_down(
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -169,6 +177,9 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
 {
        struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -177,6 +188,9 @@ static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
 {
        struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
 
+       if (IS_ERR(ipcp))
+               return (struct shmid_kernel *)ipcp;
+
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
index 1aa0ebf..76c1f34 100644 (file)
@@ -802,8 +802,8 @@ struct ipc_proc_iter {
 /*
  * This routine locks the ipc structure found at least at position pos.
  */
-struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
-                                       loff_t *new_pos)
+static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
+                                             loff_t *new_pos)
 {
        struct kern_ipc_perm *ipc;
        int total, id;
index 9d3d0f0..eb9934a 100644 (file)
@@ -1590,8 +1590,6 @@ repeat:
                                        goto repeat;
                                if (retval != 0) /* He released the lock.  */
                                        goto end;
-                       } else if (p->exit_state == EXIT_DEAD) {
-                               continue;
                        } else if (p->exit_state == EXIT_ZOMBIE) {
                                /*
                                 * Eligible but we cannot release it yet:
@@ -1606,7 +1604,7 @@ repeat:
                                /* He released the lock.  */
                                if (retval != 0)
                                        goto end;
-                       } else {
+                       } else if (p->exit_state != EXIT_DEAD) {
 check_continued:
                                /*
                                 * It's running now, so it might later
index 2b55b74..3995297 100644 (file)
@@ -1399,7 +1399,7 @@ fork_out:
        return ERR_PTR(retval);
 }
 
-noinline struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs)
+noinline struct pt_regs * __cpuinit __attribute__((weak)) idle_regs(struct pt_regs *regs)
 {
        memset(regs, 0, sizeof(struct pt_regs));
        return regs;
@@ -1510,7 +1510,7 @@ long do_fork(unsigned long clone_flags,
                if (!(clone_flags & CLONE_STOPPED))
                        wake_up_new_task(p, clone_flags);
                else
-                       p->state = TASK_STOPPED;
+                       __set_task_state(p, TASK_STOPPED);
 
                if (unlikely (trace)) {
                        current->ptrace_message = nr;
index 7dadc71..f091d13 100644 (file)
@@ -53,14 +53,6 @@ static inline int is_kernel_inittext(unsigned long addr)
        return 0;
 }
 
-static inline int is_kernel_extratext(unsigned long addr)
-{
-       if (addr >= (unsigned long)_sextratext
-           && addr <= (unsigned long)_eextratext)
-               return 1;
-       return 0;
-}
-
 static inline int is_kernel_text(unsigned long addr)
 {
        if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)
@@ -80,8 +72,7 @@ static int is_ksym_addr(unsigned long addr)
        if (all_var)
                return is_kernel(addr);
 
-       return is_kernel_text(addr) || is_kernel_inittext(addr) ||
-               is_kernel_extratext(addr);
+       return is_kernel_text(addr) || is_kernel_inittext(addr);
 }
 
 /* expand a compressed symbol data into the resulting uncompressed string,
index d0493ea..7a86e64 100644 (file)
@@ -699,6 +699,12 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p,
                                 struct kretprobe_instance, uflist);
                ri->rp = rp;
                ri->task = current;
+
+               if (rp->entry_handler && rp->entry_handler(ri, regs)) {
+                       spin_unlock_irqrestore(&kretprobe_lock, flags);
+                       return 0;
+               }
+
                arch_prepare_kretprobe(ri, regs);
 
                /* XXX(hch): why is there no hlist_move_head? */
@@ -745,7 +751,8 @@ int __kprobes register_kretprobe(struct kretprobe *rp)
        INIT_HLIST_HEAD(&rp->used_instances);
        INIT_HLIST_HEAD(&rp->free_instances);
        for (i = 0; i < rp->maxactive; i++) {
-               inst = kmalloc(sizeof(struct kretprobe_instance), GFP_KERNEL);
+               inst = kmalloc(sizeof(struct kretprobe_instance) +
+                              rp->data_size, GFP_KERNEL);
                if (inst == NULL) {
                        free_rp_inst(rp);
                        return -ENOMEM;
index 4253f47..643360d 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/notifier.h>
 #include <linux/rcupdate.h>
 #include <linux/vmalloc.h>
+#include <linux/reboot.h>
 
 /*
  *     Notifier list for kernel code which wants to be called
index 42fe5e6..e28c706 100644 (file)
@@ -272,7 +272,7 @@ static int param_array(const char *name,
                       unsigned int min, unsigned int max,
                       void *elem, int elemsize,
                       int (*set)(const char *, struct kernel_param *kp),
-                      int *num)
+                      unsigned int *num)
 {
        int ret;
        struct kernel_param kp;
index 29ae1e9..4a09062 100644 (file)
@@ -93,16 +93,16 @@ static int console_locked, console_suspended;
  */
 static DEFINE_SPINLOCK(logbuf_lock);
 
-#define LOG_BUF_MASK   (log_buf_len-1)
+#define LOG_BUF_MASK (log_buf_len-1)
 #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
 
 /*
  * The indices into log_buf are not constrained to log_buf_len - they
  * must be masked before subscripting
  */
-static unsigned long log_start;        /* Index into log_buf: next char to be read by syslog() */
-static unsigned long con_start;        /* Index into log_buf: next char to be sent to consoles */
-static unsigned long log_end;  /* Index into log_buf: most-recently-written-char + 1 */
+static unsigned log_start;     /* Index into log_buf: next char to be read by syslog() */
+static unsigned con_start;     /* Index into log_buf: next char to be sent to consoles */
+static unsigned log_end;       /* Index into log_buf: most-recently-written-char + 1 */
 
 /*
  *     Array of consoles built from command line options (console=)
@@ -128,17 +128,17 @@ static int console_may_schedule;
 static char __log_buf[__LOG_BUF_LEN];
 static char *log_buf = __log_buf;
 static int log_buf_len = __LOG_BUF_LEN;
-static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */
+static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
 
 static int __init log_buf_len_setup(char *str)
 {
-       unsigned long size = memparse(str, &str);
+       unsigned size = memparse(str, &str);
        unsigned long flags;
 
        if (size)
                size = roundup_pow_of_two(size);
        if (size > log_buf_len) {
-               unsigned long start, dest_idx, offset;
+               unsigned start, dest_idx, offset;
                char *new_log_buf;
 
                new_log_buf = alloc_bootmem(size);
@@ -295,7 +295,7 @@ int log_buf_read(int idx)
  */
 int do_syslog(int type, char __user *buf, int len)
 {
-       unsigned long i, j, limit, count;
+       unsigned i, j, limit, count;
        int do_clear = 0;
        char c;
        int error = 0;
@@ -436,7 +436,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len)
 /*
  * Call the console drivers on a range of log_buf
  */
-static void __call_console_drivers(unsigned long start, unsigned long end)
+static void __call_console_drivers(unsigned start, unsigned end)
 {
        struct console *con;
 
@@ -463,8 +463,8 @@ early_param("ignore_loglevel", ignore_loglevel_setup);
 /*
  * Write out chars from start to end - 1 inclusive
  */
-static void _call_console_drivers(unsigned long start,
-                               unsigned long end, int msg_log_level)
+static void _call_console_drivers(unsigned start,
+                               unsigned end, int msg_log_level)
 {
        if ((msg_log_level < console_loglevel || ignore_loglevel) &&
                        console_drivers && start != end) {
@@ -484,12 +484,12 @@ static void _call_console_drivers(unsigned long start,
  * log_buf[start] to log_buf[end - 1].
  * The console_sem must be held.
  */
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
 {
-       unsigned long cur_index, start_print;
+       unsigned cur_index, start_print;
        static int msg_level = -1;
 
-       BUG_ON(((long)(start - end)) > 0);
+       BUG_ON(((int)(start - end)) > 0);
 
        cur_index = start;
        start_print = start;
@@ -790,7 +790,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len)
        return -ENOSYS;
 }
 
-static void call_console_drivers(unsigned long start, unsigned long end)
+static void call_console_drivers(unsigned start, unsigned end)
 {
 }
 
@@ -983,8 +983,8 @@ void wake_up_klogd(void)
 void release_console_sem(void)
 {
        unsigned long flags;
-       unsigned long _con_start, _log_end;
-       unsigned long wake_klogd = 0;
+       unsigned _con_start, _log_end;
+       unsigned wake_klogd = 0;
 
        if (console_suspended) {
                up(&secondary_console_sem);
@@ -1275,7 +1275,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
 int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
 {
        static DEFINE_SPINLOCK(ratelimit_lock);
-       static unsigned long toks = 10 * 5 * HZ;
+       static unsigned toks = 10 * 5 * HZ;
        static unsigned long last_msg;
        static int missed;
        unsigned long flags;
index b0d4ab4..628b03a 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/signal.h>
 #include <linux/audit.h>
 #include <linux/pid_namespace.h>
+#include <linux/syscalls.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -53,7 +54,7 @@ void ptrace_untrace(struct task_struct *child)
        spin_lock(&child->sighand->siglock);
        if (task_is_traced(child)) {
                if (child->signal->flags & SIGNAL_STOP_STOPPED) {
-                       child->state = TASK_STOPPED;
+                       __set_task_state(child, TASK_STOPPED);
                } else {
                        signal_wake_up(child, 1);
                }
@@ -103,18 +104,16 @@ int ptrace_check_attach(struct task_struct *child, int kill)
            && child->signal != NULL) {
                ret = 0;
                spin_lock_irq(&child->sighand->siglock);
-               if (task_is_stopped(child)) {
+               if (task_is_stopped(child))
                        child->state = TASK_TRACED;
-               } else if (!task_is_traced(child) && !kill) {
+               else if (!task_is_traced(child) && !kill)
                        ret = -ESRCH;
-               }
                spin_unlock_irq(&child->sighand->siglock);
        }
        read_unlock(&tasklist_lock);
 
-       if (!ret && !kill) {
+       if (!ret && !kill)
                wait_task_inactive(child);
-       }
 
        /* All systems go.. */
        return ret;
index 7c03733..d080b9d 100644 (file)
@@ -37,37 +37,31 @@ static void relay_file_mmap_close(struct vm_area_struct *vma)
 }
 
 /*
- * nopage() vm_op implementation for relay file mapping.
+ * fault() vm_op implementation for relay file mapping.
  */
-static struct page *relay_buf_nopage(struct vm_area_struct *vma,
-                                    unsigned long address,
-                                    int *type)
+static int relay_buf_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct page *page;
        struct rchan_buf *buf = vma->vm_private_data;
-       unsigned long offset = address - vma->vm_start;
+       pgoff_t pgoff = vmf->pgoff;
 
-       if (address > vma->vm_end)
-               return NOPAGE_SIGBUS; /* Disallow mremap */
        if (!buf)
-               return NOPAGE_OOM;
+               return VM_FAULT_OOM;
 
-       page = vmalloc_to_page(buf->start + offset);
+       page = vmalloc_to_page(buf->start + (pgoff << PAGE_SHIFT));
        if (!page)
-               return NOPAGE_OOM;
+               return VM_FAULT_SIGBUS;
        get_page(page);
+       vmf->page = page;
 
-       if (type)
-               *type = VM_FAULT_MINOR;
-
-       return page;
+       return 0;
 }
 
 /*
  * vm_ops for relay file mappings.
  */
 static struct vm_operations_struct relay_file_mmap_ops = {
-       .nopage = relay_buf_nopage,
+       .fault = relay_buf_fault,
        .close = relay_file_mmap_close,
 };
 
index 6a5f97c..5d30ff5 100644 (file)
@@ -1577,6 +1577,17 @@ static inline int may_ptrace_stop(void)
        return 1;
 }
 
+/*
+ * Return nonzero if there is a SIGKILL that should be waking us up.
+ * Called with the siglock held.
+ */
+static int sigkill_pending(struct task_struct *tsk)
+{
+       return ((sigismember(&tsk->pending.signal, SIGKILL) ||
+                sigismember(&tsk->signal->shared_pending.signal, SIGKILL)) &&
+               !unlikely(sigismember(&tsk->blocked, SIGKILL)));
+}
+
 /*
  * This must be called with current->sighand->siglock held.
  *
@@ -1590,6 +1601,26 @@ static inline int may_ptrace_stop(void)
  */
 static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
 {
+       int killed = 0;
+
+       if (arch_ptrace_stop_needed(exit_code, info)) {
+               /*
+                * The arch code has something special to do before a
+                * ptrace stop.  This is allowed to block, e.g. for faults
+                * on user stack pages.  We can't keep the siglock while
+                * calling arch_ptrace_stop, so we must release it now.
+                * To preserve proper semantics, we must do this before
+                * any signal bookkeeping like checking group_stop_count.
+                * Meanwhile, a SIGKILL could come in before we retake the
+                * siglock.  That must prevent us from sleeping in TASK_TRACED.
+                * So after regaining the lock, we must check for SIGKILL.
+                */
+               spin_unlock_irq(&current->sighand->siglock);
+               arch_ptrace_stop(exit_code, info);
+               spin_lock_irq(&current->sighand->siglock);
+               killed = sigkill_pending(current);
+       }
+
        /*
         * If there is a group stop in progress,
         * we must participate in the bookkeeping.
@@ -1601,11 +1632,11 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
        current->exit_code = exit_code;
 
        /* Let the debugger run.  */
-       set_current_state(TASK_TRACED);
+       __set_current_state(TASK_TRACED);
        spin_unlock_irq(&current->sighand->siglock);
        try_to_freeze();
        read_lock(&tasklist_lock);
-       if (may_ptrace_stop()) {
+       if (!unlikely(killed) && may_ptrace_stop()) {
                do_notify_parent_cldstop(current, CLD_TRAPPED);
                read_unlock(&tasklist_lock);
                schedule();
index 3507cab..b0aeeaf 100644 (file)
@@ -74,7 +74,7 @@ static int srcu_readers_active_idx(struct srcu_struct *sp, int idx)
  * severe errors when invoked on an active srcu_struct.  That said, it
  * can be useful as an error check at cleanup time.
  */
-int srcu_readers_active(struct srcu_struct *sp)
+static int srcu_readers_active(struct srcu_struct *sp)
 {
        return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1);
 }
@@ -255,4 +255,3 @@ EXPORT_SYMBOL_GPL(srcu_read_lock);
 EXPORT_SYMBOL_GPL(srcu_read_unlock);
 EXPORT_SYMBOL_GPL(synchronize_srcu);
 EXPORT_SYMBOL_GPL(srcu_batches_completed);
-EXPORT_SYMBOL_GPL(srcu_readers_active);
index 51b5ee5..6f4e0e1 100644 (file)
@@ -29,7 +29,6 @@ enum stopmachine_state {
 static enum stopmachine_state stopmachine_state;
 static unsigned int stopmachine_num_threads;
 static atomic_t stopmachine_thread_ack;
-static DECLARE_MUTEX(stopmachine_mutex);
 
 static int stopmachine(void *cpu)
 {
@@ -170,6 +169,7 @@ static int do_stop(void *_smdata)
 struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
                                       unsigned int cpu)
 {
+       static DEFINE_MUTEX(stopmachine_mutex);
        struct stop_machine_data smdata;
        struct task_struct *p;
 
@@ -177,7 +177,7 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
        smdata.data = data;
        init_completion(&smdata.done);
 
-       down(&stopmachine_mutex);
+       mutex_lock(&stopmachine_mutex);
 
        /* If they don't care which CPU fn runs on, bind to any online one. */
        if (cpu == NR_CPUS)
@@ -193,7 +193,7 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
                wake_up_process(p);
                wait_for_completion(&smdata.done);
        }
-       up(&stopmachine_mutex);
+       mutex_unlock(&stopmachine_mutex);
        return p;
 }
 
index 53de35f..e3c08d4 100644 (file)
@@ -1145,16 +1145,16 @@ static int groups_to_user(gid_t __user *grouplist,
     struct group_info *group_info)
 {
        int i;
-       int count = group_info->ngroups;
+       unsigned int count = group_info->ngroups;
 
        for (i = 0; i < group_info->nblocks; i++) {
-               int cp_count = min(NGROUPS_PER_BLOCK, count);
-               int off = i * NGROUPS_PER_BLOCK;
-               int len = cp_count * sizeof(*grouplist);
+               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+               unsigned int len = cp_count * sizeof(*grouplist);
 
-               if (copy_to_user(grouplist+off, group_info->blocks[i], len))
+               if (copy_to_user(grouplist, group_info->blocks[i], len))
                        return -EFAULT;
 
+               grouplist += NGROUPS_PER_BLOCK;
                count -= cp_count;
        }
        return 0;
@@ -1165,16 +1165,16 @@ static int groups_from_user(struct group_info *group_info,
     gid_t __user *grouplist)
 {
        int i;
-       int count = group_info->ngroups;
+       unsigned int count = group_info->ngroups;
 
        for (i = 0; i < group_info->nblocks; i++) {
-               int cp_count = min(NGROUPS_PER_BLOCK, count);
-               int off = i * NGROUPS_PER_BLOCK;
-               int len = cp_count * sizeof(*grouplist);
+               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+               unsigned int len = cp_count * sizeof(*grouplist);
 
-               if (copy_from_user(group_info->blocks[i], grouplist+off, len))
+               if (copy_from_user(group_info->blocks[i], grouplist, len))
                        return -EFAULT;
 
+               grouplist += NGROUPS_PER_BLOCK;
                count -= cp_count;
        }
        return 0;
@@ -1472,7 +1472,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
        if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
            !capable(CAP_SYS_RESOURCE))
                return -EPERM;
-       if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN)
+       if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
                return -EPERM;
 
        retval = security_task_setrlimit(resource, &new_rlim);
index 5e2ad5b..86daaa2 100644 (file)
@@ -1202,6 +1202,14 @@ static struct ctl_table fs_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "nr_open",
+               .data           = &sysctl_nr_open,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
        {
                .ctl_name       = FS_DENTRY,
                .procname       = "dentry-state",
index 88cdb10..06b6395 100644 (file)
@@ -135,6 +135,12 @@ static int test_jprobe(void)
 #ifdef CONFIG_KRETPROBES
 static u32 krph_val;
 
+static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       krph_val = (rand1 / div_factor);
+       return 0;
+}
+
 static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        unsigned long ret = regs_return_value(regs);
@@ -144,13 +150,19 @@ static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
                printk(KERN_ERR "Kprobe smoke test failed: "
                                "incorrect value in kretprobe handler\n");
        }
+       if (krph_val == 0) {
+               handler_errors++;
+               printk(KERN_ERR "Kprobe smoke test failed: "
+                               "call to kretprobe entry handler failed\n");
+       }
 
-       krph_val = (rand1 / div_factor);
+       krph_val = rand1;
        return 0;
 }
 
 static struct kretprobe rp = {
        .handler        = return_handler,
+       .entry_handler  = entry_handler,
        .kp.symbol_name = "kprobe_target"
 };
 
@@ -167,7 +179,7 @@ static int test_kretprobe(void)
 
        ret = kprobe_target(rand1);
        unregister_kretprobe(&rp);
-       if (krph_val == 0) {
+       if (krph_val != rand1) {
                printk(KERN_ERR "Kprobe smoke test failed: "
                                "kretprobe handler not called\n");
                handler_errors++;
index 4064c05..33af3e5 100644 (file)
@@ -566,7 +566,11 @@ EXPORT_SYMBOL(jiffies_to_timeval);
 clock_t jiffies_to_clock_t(long x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+# if HZ < USER_HZ
+       return x * (USER_HZ / HZ);
+# else
        return x / (HZ / USER_HZ);
+# endif
 #else
        u64 tmp = (u64)x * TICK_NSEC;
        do_div(tmp, (NSEC_PER_SEC / USER_HZ));
@@ -599,7 +603,14 @@ EXPORT_SYMBOL(clock_t_to_jiffies);
 u64 jiffies_64_to_clock_t(u64 x)
 {
 #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
+# if HZ < USER_HZ
+       x *= USER_HZ;
+       do_div(x, HZ);
+# elif HZ > USER_HZ
        do_div(x, HZ / USER_HZ);
+# else
+       /* Nothing to do */
+# endif
 #else
        /*
         * There are better ways that don't overflow early,
@@ -611,7 +622,6 @@ u64 jiffies_64_to_clock_t(u64 x)
 #endif
        return x;
 }
-
 EXPORT_SYMBOL(jiffies_64_to_clock_t);
 
 u64 nsec_to_clock_t(u64 x)
@@ -646,7 +656,6 @@ u64 get_jiffies_64(void)
        } while (read_seqretry(&xtime_lock, seq));
        return ret;
 }
-
 EXPORT_SYMBOL(get_jiffies_64);
 #endif
 
index 6e9259a..81afb39 100644 (file)
@@ -363,15 +363,13 @@ void clocksource_unregister(struct clocksource *cs)
 static ssize_t
 sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
 {
-       char *curr = buf;
+       ssize_t count = 0;
 
        spin_lock_irq(&clocksource_lock);
-       curr += sprintf(curr, "%s ", curr_clocksource->name);
+       count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name);
        spin_unlock_irq(&clocksource_lock);
 
-       curr += sprintf(curr, "\n");
-
-       return curr - buf;
+       return count;
 }
 
 /**
@@ -439,17 +437,20 @@ static ssize_t
 sysfs_show_available_clocksources(struct sys_device *dev, char *buf)
 {
        struct clocksource *src;
-       char *curr = buf;
+       ssize_t count = 0;
 
        spin_lock_irq(&clocksource_lock);
        list_for_each_entry(src, &clocksource_list, list) {
-               curr += sprintf(curr, "%s ", src->name);
+               count += snprintf(buf + count,
+                                 max((ssize_t)PAGE_SIZE - count, (ssize_t)0),
+                                 "%s ", src->name);
        }
        spin_unlock_irq(&clocksource_lock);
 
-       curr += sprintf(curr, "\n");
+       count += snprintf(buf + count,
+                         max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "\n");
 
-       return curr - buf;
+       return count;
 }
 
 /*
index 9fbb472..70b29b5 100644 (file)
@@ -818,12 +818,14 @@ unsigned long next_timer_interrupt(void)
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 void account_process_tick(struct task_struct *p, int user_tick)
 {
+       cputime_t one_jiffy = jiffies_to_cputime(1);
+
        if (user_tick) {
-               account_user_time(p, jiffies_to_cputime(1));
-               account_user_time_scaled(p, jiffies_to_cputime(1));
+               account_user_time(p, one_jiffy);
+               account_user_time_scaled(p, cputime_to_scaled(one_jiffy));
        } else {
-               account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1));
-               account_system_time_scaled(p, jiffies_to_cputime(1));
+               account_system_time(p, HARDIRQ_OFFSET, one_jiffy);
+               account_system_time_scaled(p, cputime_to_scaled(one_jiffy));
        }
 }
 #endif
index 463f456..179c087 100644 (file)
@@ -57,10 +57,10 @@ search_extable(const struct exception_table_entry *first,
        while (first <= last) {
                const struct exception_table_entry *mid;
 
-               mid = (last - first) / 2 + first;
+               mid = ((last - first) >> 1) + first;
                /*
-                * careful, the distance between entries can be
-                * larger than 2GB:
+                * careful, the distance between value and insn
+                * can be larger than MAX_LONG:
                 */
                if (mid->insn < value)
                        first = mid + 1;
index eddc9b3..6c90fb9 100644 (file)
@@ -42,7 +42,9 @@ unsigned int debug_smp_processor_id(void)
        if (!printk_ratelimit())
                goto out_enable;
 
-       printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid);
+       printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] "
+                       "code: %s/%d\n",
+                       preempt_count() - 1, current->comm, current->pid);
        print_symbol("caller is %s\n", (long)__builtin_return_address(0));
        dump_stack();
 
index 00b0262..7e58322 100644 (file)
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(__percpu_populate_mask);
  */
 void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
 {
-       void *pdata = kzalloc(sizeof(struct percpu_data), gfp);
+       void *pdata = kzalloc(nr_cpu_ids * sizeof(void *), gfp);
        void *__pdata = __percpu_disguise(pdata);
 
        if (unlikely(!pdata))
index 749fa04..85c680a 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/net.h>
 
 #include <net/ip_vs.h>
 
@@ -169,7 +170,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                                 */
                                if (mark->cw == 0) {
                                        mark->cl = &svc->destinations;
-                                       IP_VS_INFO("ip_vs_wrr_schedule(): "
+                                       IP_VS_ERR_RL("ip_vs_wrr_schedule(): "
                                                   "no available servers\n");
                                        dest = NULL;
                                        goto out;
index e77592d..45c7c0c 100644 (file)
@@ -1,6 +1,5 @@
 config MAC80211
        tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
-       depends on EXPERIMENTAL
        select CRYPTO
        select CRYPTO_ECB
        select CRYPTO_ARC4
index 8d76986..971b867 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/if_vlan.h>
 
 #include <net/pkt_cls.h>
 #include <net/ip.h>
@@ -270,6 +271,15 @@ static u32 flow_get_skgid(const struct sk_buff *skb)
        return 0;
 }
 
+static u32 flow_get_vlan_tag(const struct sk_buff *skb)
+{
+       u16 uninitialized_var(tag);
+
+       if (vlan_get_tag(skb, &tag) < 0)
+               return 0;
+       return tag & VLAN_VID_MASK;
+}
+
 static u32 flow_key_get(const struct sk_buff *skb, int key)
 {
        switch (key) {
@@ -305,6 +315,8 @@ static u32 flow_key_get(const struct sk_buff *skb, int key)
                return flow_get_skuid(skb);
        case FLOW_KEY_SKGID:
                return flow_get_skgid(skb);
+       case FLOW_KEY_VLAN_TAG:
+               return flow_get_vlan_tag(skb);
        default:
                WARN_ON(1);
                return 0;
@@ -402,12 +414,13 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
 
        if (tb[TCA_FLOW_KEYS]) {
                keymask = nla_get_u32(tb[TCA_FLOW_KEYS]);
-               if (fls(keymask) - 1 > FLOW_KEY_MAX)
-                       return -EOPNOTSUPP;
 
                nkeys = hweight32(keymask);
                if (nkeys == 0)
                        return -EINVAL;
+
+               if (fls(keymask) - 1 > FLOW_KEY_MAX)
+                       return -EOPNOTSUPP;
        }
 
        err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
index 9c2ec19..2a7e648 100644 (file)
@@ -176,7 +176,7 @@ META_COLLECTOR(var_dev)
 
 META_COLLECTOR(int_vlan_tag)
 {
-       unsigned short tag;
+       unsigned short uninitialized_var(tag);
        if (vlan_get_tag(skb, &tag) < 0)
                *err = -1;
        else
index d716b76..340ad69 100755 (executable)
@@ -2,7 +2,7 @@
 
 #      Check the stack usage of functions
 #
-#      Copyright Joern Engel <joern@wh.fh-wedel.de>
+#      Copyright Joern Engel <joern@lazybastard.org>
 #      Inspired by Linus Torvalds
 #      Original idea maybe from Keith Owens
 #      s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
index 1f11d84..c912137 100644 (file)
 
 #define KSYM_NAME_LEN          128
 
-
 struct sym_entry {
        unsigned long long addr;
        unsigned int len;
+       unsigned int start_pos;
        unsigned char *sym;
 };
 
-
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
-static unsigned long long _text, _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
+static unsigned long long _text, _stext, _etext, _sinittext, _einittext;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
 
@@ -99,10 +98,6 @@ static int read_symbol(FILE *in, struct sym_entry *s)
                _sinittext = s->addr;
        else if (strcmp(sym, "_einittext") == 0)
                _einittext = s->addr;
-       else if (strcmp(sym, "_sextratext") == 0)
-               _sextratext = s->addr;
-       else if (strcmp(sym, "_eextratext") == 0)
-               _eextratext = s->addr;
        else if (toupper(stype) == 'A')
        {
                /* Keep these useful absolute symbols */
@@ -165,18 +160,18 @@ static int symbol_valid(struct sym_entry *s)
         * and inittext sections are discarded */
        if (!all_symbols) {
                if ((s->addr < _stext || s->addr > _etext)
-                   && (s->addr < _sinittext || s->addr > _einittext)
-                   && (s->addr < _sextratext || s->addr > _eextratext))
+                   && (s->addr < _sinittext || s->addr > _einittext))
                        return 0;
                /* Corner case.  Discard any symbols with the same value as
-                * _etext _einittext or _eextratext; they can move between pass
-                * 1 and 2 when the kallsyms data are added.  If these symbols
-                * move then they may get dropped in pass 2, which breaks the
-                * kallsyms rules.
+                * _etext _einittext; they can move between pass 1 and 2 when
+                * the kallsyms data are added.  If these symbols move then
+                * they may get dropped in pass 2, which breaks the kallsyms
+                * rules.
                 */
-               if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
-                   (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
-                   (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
+               if ((s->addr == _etext &&
+                               strcmp((char *)s->sym + offset, "_etext")) ||
+                   (s->addr == _einittext &&
+                               strcmp((char *)s->sym + offset, "_einittext")))
                        return 0;
        }
 
@@ -202,8 +197,10 @@ static void read_map(FILE *in)
                                exit (1);
                        }
                }
-               if (read_symbol(in, &table[table_cnt]) == 0)
+               if (read_symbol(in, &table[table_cnt]) == 0) {
+                       table[table_cnt].start_pos = table_cnt;
                        table_cnt++;
+               }
        }
 }
 
@@ -506,6 +503,35 @@ static void optimize_token_table(void)
        optimize_result();
 }
 
+static int compare_symbols(const void *a, const void *b)
+{
+       const struct sym_entry *sa;
+       const struct sym_entry *sb;
+       int wa, wb;
+
+       sa = a;
+       sb = b;
+
+       /* sort by address first */
+       if (sa->addr > sb->addr)
+               return 1;
+       if (sa->addr < sb->addr)
+               return -1;
+
+       /* sort by "weakness" type */
+       wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W');
+       wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W');
+       if (wa != wb)
+               return wa - wb;
+
+       /* sort by initial order, so that other symbols are left undisturbed */
+       return sa->start_pos - sb->start_pos;
+}
+
+static void sort_symbols(void)
+{
+       qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
+}
 
 int main(int argc, char **argv)
 {
@@ -527,6 +553,7 @@ int main(int argc, char **argv)
                usage();
 
        read_map(stdin);
+       sort_symbols();
        optimize_token_table();
        write_src();
 
index 25ffe1b..5dfc206 100644 (file)
@@ -104,6 +104,24 @@ config SECURITY_ROOTPLUG
          
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_DEFAULT_MMAP_MIN_ADDR
+        int "Low address space to protect from user allocation"
+        depends on SECURITY
+        default 0
+        help
+         This is the portion of low virtual memory which should be protected
+         from userspace allocation.  Keeping a user from writing to low pages
+         can help reduce the impact of kernel NULL pointer bugs.
+
+         For most users with lots of address space a value of 65536 is
+         reasonable and should cause no problems.  Programs which use vm86
+         functionality would either need additional permissions from either
+         the LSM or the capabilities module or have this protection disabled.
+
+         This value can be changed after boot using the
+         /proc/sys/vm/mmap_min_addr tunable.
+
+
 source security/selinux/Kconfig
 source security/smack/Kconfig
 
index b6c57a6..d15e56c 100644 (file)
@@ -23,7 +23,9 @@ extern struct security_operations dummy_security_ops;
 extern void security_fixup_ops(struct security_operations *ops);
 
 struct security_operations *security_ops;      /* Initialized to NULL */
-unsigned long mmap_min_addr;           /* 0 means no protection */
+
+/* amount of vm to protect from userspace access */
+unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR;
 
 static inline int verify(struct security_operations *ops)
 {
index 23137c1..837ce42 100644 (file)
@@ -107,7 +107,6 @@ int security_get_classes(char ***classes, int *nclasses);
 int security_get_permissions(char *class, char ***perms, int *nperms);
 int security_get_reject_unknown(void);
 int security_get_allow_unknown(void);
-int security_get_policycaps(int *len, int **values);
 
 #define SECURITY_FS_USE_XATTR          1 /* use xattr */
 #define SECURITY_FS_USE_TRANS          2 /* use transition SIDs, e.g. devpts/tmpfs */
index fced6bc..f374186 100644 (file)
@@ -2245,39 +2245,6 @@ int security_get_allow_unknown(void)
        return policydb.allow_unknown;
 }
 
-/**
- * security_get_policycaps - Query the loaded policy for its capabilities
- * @len: the number of capability bits
- * @values: the capability bit array
- *
- * Description:
- * Get an array of the policy capabilities in @values where each entry in
- * @values is either true (1) or false (0) depending the policy's support of
- * that feature.  The policy capabilities are defined by the
- * POLICYDB_CAPABILITY_* enums.  The size of the array is stored in @len and it
- * is up to the caller to free the array in @values.  Returns zero on success,
- * negative values on failure.
- *
- */
-int security_get_policycaps(int *len, int **values)
-{
-       int rc = -ENOMEM;
-       unsigned int iter;
-
-       POLICY_RDLOCK;
-
-       *values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
-       if (*values == NULL)
-               goto out;
-       for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
-               (*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
-       *len = POLICYDB_CAPABILITY_MAX;
-
-out:
-       POLICY_RDUNLOCK;
-       return rc;
-}
-
 /**
  * security_policycap_supported - Check for a specific policy capability
  * @req_cap: capability
index f883c4b..1f86299 100644 (file)
@@ -6,7 +6,6 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_SOUND_OSS)                += sound.o
-obj-$(CONFIG_SOUND_CS4232)     += cs4232.o ad1848.o 
 
 # Please leave it as is, cause the link order is significant !
 
@@ -16,7 +15,6 @@ obj-$(CONFIG_SOUND_AEDSP16)   += aedsp16.o
 obj-$(CONFIG_SOUND_PSS)                += pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)       += trix.o ad1848.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SSCAPE)     += sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_CS4232)     += cs4232.o uart401.o
 obj-$(CONFIG_SOUND_MSS)                += ad1848.o
 obj-$(CONFIG_SOUND_PAS)                += pas2.o sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SB)         += sb.o sb_lib.o uart401.o
@@ -27,19 +25,12 @@ obj-$(CONFIG_SOUND_YM3812)  += opl3.o
 obj-$(CONFIG_SOUND_VMIDI)      += v_midi.o
 obj-$(CONFIG_SOUND_VIDC)       += vidc_mod.o
 obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
-
-obj-$(CONFIG_SOUND_VIA82CXXX)  += via82cxxx_audio.o ac97_codec.o
-ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
-  obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o
-endif
 obj-$(CONFIG_SOUND_MSNDCLAS)   += msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDPIN)    += msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_VWSND)      += vwsnd.o
-obj-$(CONFIG_SOUND_ICH)                += i810_audio.o ac97_codec.o
 obj-$(CONFIG_SOUND_AU1550_AC97)        += au1550_ac97.o ac97_codec.o
 obj-$(CONFIG_SOUND_TRIDENT)    += trident.o ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)        += swarm_cs4297a.o
-obj-$(CONFIG_SOUND_BT878)      += btaudio.o
 
 obj-$(CONFIG_SOUND_WM97XX)     += ac97_plugin_wm97xx.o
 
index fef56ca..87a6726 100644 (file)
@@ -189,42 +189,6 @@ static const struct {
        {0x57454301, "Winbond 83971D",          &null_ops},
 };
 
-static const char *ac97_stereo_enhancements[] =
-{
-       /*   0 */ "No 3D Stereo Enhancement",
-       /*   1 */ "Analog Devices Phat Stereo",
-       /*   2 */ "Creative Stereo Enhancement",
-       /*   3 */ "National Semi 3D Stereo Enhancement",
-       /*   4 */ "YAMAHA Ymersion",
-       /*   5 */ "BBE 3D Stereo Enhancement",
-       /*   6 */ "Crystal Semi 3D Stereo Enhancement",
-       /*   7 */ "Qsound QXpander",
-       /*   8 */ "Spatializer 3D Stereo Enhancement",
-       /*   9 */ "SRS 3D Stereo Enhancement",
-       /*  10 */ "Platform Tech 3D Stereo Enhancement",
-       /*  11 */ "AKM 3D Audio",
-       /*  12 */ "Aureal Stereo Enhancement",
-       /*  13 */ "Aztech 3D Enhancement",
-       /*  14 */ "Binaura 3D Audio Enhancement",
-       /*  15 */ "ESS Technology Stereo Enhancement",
-       /*  16 */ "Harman International VMAx",
-       /*  17 */ "Nvidea 3D Stereo Enhancement",
-       /*  18 */ "Philips Incredible Sound",
-       /*  19 */ "Texas Instruments 3D Stereo Enhancement",
-       /*  20 */ "VLSI Technology 3D Stereo Enhancement",
-       /*  21 */ "TriTech 3D Stereo Enhancement",
-       /*  22 */ "Realtek 3D Stereo Enhancement",
-       /*  23 */ "Samsung 3D Stereo Enhancement",
-       /*  24 */ "Wolfson Microelectronics 3D Enhancement",
-       /*  25 */ "Delta Integration 3D Enhancement",
-       /*  26 */ "SigmaTel 3D Enhancement",
-       /*  27 */ "Winbond 3D Stereo Enhancement",
-       /*  28 */ "Rockwell 3D Stereo Enhancement",
-       /*  29 */ "Reserved 29",
-       /*  30 */ "Reserved 30",
-       /*  31 */ "Reserved 31"
-};
-
 /* this table has default mixer values for all OSS mixers. */
 static struct mixer_defaults {
        int mixer;
@@ -614,83 +578,6 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned
        return -EINVAL;
 }
 
-/* entry point for /proc/driver/controller_vendor/ac97/%d */
-int ac97_read_proc (char *page, char **start, off_t off,
-                   int count, int *eof, void *data)
-{
-       int len = 0, cap, extid, val, id1, id2;
-       struct ac97_codec *codec;
-       int is_ac97_20 = 0;
-
-       if ((codec = data) == NULL)
-               return -ENODEV;
-
-       id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
-       id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
-       len += sprintf (page+len, "Vendor name      : %s\n", codec->name);
-       len += sprintf (page+len, "Vendor id        : %04X %04X\n", id1, id2);
-
-       extid = codec->codec_read(codec, AC97_EXTENDED_ID);
-       extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
-       len += sprintf (page+len, "AC97 Version     : %s\n",
-                       extid ? "2.0 or later" : "1.0");
-       if (extid) is_ac97_20 = 1;
-
-       cap = codec->codec_read(codec, AC97_RESET);
-       len += sprintf (page+len, "Capabilities     :%s%s%s%s%s%s\n",
-                       cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
-                       cap & 0x0002 ? " -reserved1-" : "",
-                       cap & 0x0004 ? " -bass & treble-" : "",
-                       cap & 0x0008 ? " -simulated stereo-" : "",
-                       cap & 0x0010 ? " -headphone out-" : "",
-                       cap & 0x0020 ? " -loudness-" : "");
-       val = cap & 0x00c0;
-       len += sprintf (page+len, "DAC resolutions  :%s%s%s\n",
-                       " -16-bit-",
-                       val & 0x0040 ? " -18-bit-" : "",
-                       val & 0x0080 ? " -20-bit-" : "");
-       val = cap & 0x0300;
-       len += sprintf (page+len, "ADC resolutions  :%s%s%s\n",
-                       " -16-bit-",
-                       val & 0x0100 ? " -18-bit-" : "",
-                       val & 0x0200 ? " -20-bit-" : "");
-       len += sprintf (page+len, "3D enhancement   : %s\n",
-                       ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
-
-       val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
-       len += sprintf (page+len, "POP path         : %s 3D\n"
-                       "Sim. stereo      : %s\n"
-                       "3D enhancement   : %s\n"
-                       "Loudness         : %s\n"
-                       "Mono output      : %s\n"
-                       "MIC select       : %s\n"
-                       "ADC/DAC loopback : %s\n",
-                       val & 0x8000 ? "post" : "pre",
-                       val & 0x4000 ? "on" : "off",
-                       val & 0x2000 ? "on" : "off",
-                       val & 0x1000 ? "on" : "off",
-                       val & 0x0200 ? "MIC" : "MIX",
-                       val & 0x0100 ? "MIC2" : "MIC1",
-                       val & 0x0080 ? "on" : "off");
-
-       extid = codec->codec_read(codec, AC97_EXTENDED_ID);
-       cap = extid;
-       len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
-                       cap & 0x0001 ? " -var rate PCM audio-" : "",
-                       cap & 0x0002 ? " -2x PCM audio out-" : "",
-                       cap & 0x0008 ? " -var rate MIC in-" : "",
-                       cap & 0x0040 ? " -PCM center DAC-" : "",
-                       cap & 0x0080 ? " -PCM surround DAC-" : "",
-                       cap & 0x0100 ? " -PCM LFE DAC-" : "",
-                       cap & 0x0200 ? " -slot/DAC mappings-" : "");
-       if (is_ac97_20) {
-               len += sprintf (page+len, "Front DAC rate   : %d\n",
-                               codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE));
-       }
-
-       return len;
-}
-
 /**
  *     codec_id        -  Turn id1/id2 into a PnP string
  *     @id1: Vendor ID1
@@ -1313,176 +1200,5 @@ static int pt101_init(struct ac97_codec * codec)
 #endif
        
 
-EXPORT_SYMBOL(ac97_read_proc);
 EXPORT_SYMBOL(ac97_probe_codec);
 
-/*
- *     AC97 library support routines
- */    
-/**
- *     ac97_set_dac_rate       -       set codec rate adaption
- *     @codec: ac97 code
- *     @rate: rate in hertz
- *
- *     Set the DAC rate. Assumes the codec supports VRA. The caller is
- *     expected to have checked this little detail.
- */
-unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate)
-{
-       unsigned int new_rate = rate;
-       u32 dacp;
-       u32 mast_vol, phone_vol, mono_vol, pcm_vol;
-       u32 mute_vol = 0x8000;  /* The mute volume? */
-
-       if(rate != codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE))
-       {
-               /* Mute several registers */
-               mast_vol = codec->codec_read(codec, AC97_MASTER_VOL_STEREO);
-               mono_vol = codec->codec_read(codec, AC97_MASTER_VOL_MONO);
-               phone_vol = codec->codec_read(codec, AC97_HEADPHONE_VOL);
-               pcm_vol = codec->codec_read(codec, AC97_PCMOUT_VOL);
-               codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mute_vol);
-               codec->codec_write(codec, AC97_MASTER_VOL_MONO, mute_vol);
-               codec->codec_write(codec, AC97_HEADPHONE_VOL, mute_vol);
-               codec->codec_write(codec, AC97_PCMOUT_VOL, mute_vol);
-               
-               /* Power down the DAC */
-               dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200);
-               /* Load the rate and read the effective rate */
-               codec->codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate);
-               new_rate=codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE);
-               /* Power it back up */
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
-
-               /* Restore volumes */
-               codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mast_vol);
-               codec->codec_write(codec, AC97_MASTER_VOL_MONO, mono_vol);
-               codec->codec_write(codec, AC97_HEADPHONE_VOL, phone_vol);
-               codec->codec_write(codec, AC97_PCMOUT_VOL, pcm_vol);
-       }
-       return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_dac_rate);
-
-/**
- *     ac97_set_adc_rate       -       set codec rate adaption
- *     @codec: ac97 code
- *     @rate: rate in hertz
- *
- *     Set the ADC rate. Assumes the codec supports VRA. The caller is
- *     expected to have checked this little detail.
- */
-
-unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate)
-{
-       unsigned int new_rate = rate;
-       u32 dacp;
-
-       if(rate != codec->codec_read(codec, AC97_PCM_LR_ADC_RATE))
-       {
-               /* Power down the ADC */
-               dacp=codec->codec_read(codec, AC97_POWER_CONTROL);
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0100);
-               /* Load the rate and read the effective rate */
-               codec->codec_write(codec, AC97_PCM_LR_ADC_RATE, rate);
-               new_rate=codec->codec_read(codec, AC97_PCM_LR_ADC_RATE);
-               /* Power it back up */
-               codec->codec_write(codec, AC97_POWER_CONTROL, dacp);
-       }
-       return new_rate;
-}
-
-EXPORT_SYMBOL(ac97_set_adc_rate);
-
-static int swap_headphone(int remove_master)
-{
-       struct list_head *l;
-       struct ac97_codec *c;
-       
-       if (remove_master) {
-               mutex_lock(&codec_mutex);
-               list_for_each(l, &codecs)
-               {
-                       c = list_entry(l, struct ac97_codec, list);
-                       if (supported_mixer(c, SOUND_MIXER_PHONEOUT))
-                               c->supported_mixers &= ~SOUND_MASK_PHONEOUT;
-               }
-               mutex_unlock(&codec_mutex);
-       } else
-               ac97_hw[SOUND_MIXER_PHONEOUT].offset = AC97_MASTER_VOL_STEREO;
-
-       /* Scale values already match */
-       ac97_hw[SOUND_MIXER_VOLUME].offset = AC97_MASTER_VOL_MONO;
-       return 0;
-}
-
-static int apply_quirk(int quirk)
-{
-       switch (quirk) {
-       case AC97_TUNE_NONE:
-               return 0;
-       case AC97_TUNE_HP_ONLY:
-               return swap_headphone(1);
-       case AC97_TUNE_SWAP_HP:
-               return swap_headphone(0);
-       case AC97_TUNE_SWAP_SURROUND:
-               return -ENOSYS; /* not yet implemented */
-       case AC97_TUNE_AD_SHARING:
-               return -ENOSYS; /* not yet implemented */
-       case AC97_TUNE_ALC_JACK:
-               return -ENOSYS; /* not yet implemented */
-       }
-       return -EINVAL;
-}
-
-/**
- *     ac97_tune_hardware - tune up the hardware
- *     @pdev: pci_dev pointer
- *     @quirk: quirk list
- *     @override: explicit quirk value (overrides if not AC97_TUNE_DEFAULT)
- *
- *     Do some workaround for each pci device, such as renaming of the
- *     headphone (true line-out) control as "Master".
- *     The quirk-list must be terminated with a zero-filled entry.
- *
- *     Returns zero if successful, or a negative error code on failure.
- */
-
-int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override)
-{
-       int result;
-
-       if (!quirk)
-               return -EINVAL;
-
-       if (override != AC97_TUNE_DEFAULT) {
-               result = apply_quirk(override);
-               if (result < 0)
-                       printk(KERN_ERR "applying quirk type %d failed (%d)\n", override, result);
-               return result;
-       }
-
-       for (; quirk->vendor; quirk++) {
-               if (quirk->vendor != pdev->subsystem_vendor)
-                       continue;
-               if ((! quirk->mask && quirk->device == pdev->subsystem_device) ||
-                   quirk->device == (quirk->mask & pdev->subsystem_device)) {
-#ifdef DEBUG
-                       printk("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, pdev->subsystem_device);
-#endif
-                       result = apply_quirk(quirk->type);
-                       if (result < 0)
-                               printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result);
-                       return result;
-               }
-       }
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(ac97_tune_hardware);
-
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
deleted file mode 100644 (file)
index 4d5cf05..0000000
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
-    btaudio - bt878 audio dma driver for linux 2.4.x
-
-    (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/slab.h>
-#include <linux/kdev_t.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-
-/* mmio access */
-#define btwrite(dat,adr)    writel((dat), (bta->mmio+(adr)))
-#define btread(adr)         readl(bta->mmio+(adr))
-
-#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-/* registers (shifted because bta->mmio is long) */
-#define REG_INT_STAT      (0x100 >> 2)
-#define REG_INT_MASK      (0x104 >> 2)
-#define REG_GPIO_DMA_CTL  (0x10c >> 2)
-#define REG_PACKET_LEN    (0x110 >> 2)
-#define REG_RISC_STRT_ADD (0x114 >> 2)
-#define REG_RISC_COUNT    (0x120 >> 2)
-
-/* IRQ bits - REG_INT_(STAT|MASK) */
-#define IRQ_SCERR         (1 << 19)
-#define IRQ_OCERR         (1 << 18)
-#define IRQ_PABORT        (1 << 17)
-#define IRQ_RIPERR        (1 << 16)
-#define IRQ_PPERR         (1 << 15)
-#define IRQ_FDSR          (1 << 14)
-#define IRQ_FTRGT         (1 << 13)
-#define IRQ_FBUS          (1 << 12)
-#define IRQ_RISCI         (1 << 11)
-#define IRQ_OFLOW         (1 <<  3)
-
-#define IRQ_BTAUDIO       (IRQ_SCERR | IRQ_OCERR | IRQ_PABORT | IRQ_RIPERR |\
-                          IRQ_PPERR | IRQ_FDSR  | IRQ_FTRGT  | IRQ_FBUS   |\
-                          IRQ_RISCI)
-
-/* REG_GPIO_DMA_CTL bits */
-#define DMA_CTL_A_PWRDN   (1 << 26)
-#define DMA_CTL_DA_SBR    (1 << 14)
-#define DMA_CTL_DA_ES2    (1 << 13)
-#define DMA_CTL_ACAP_EN   (1 <<  4)
-#define DMA_CTL_RISC_EN   (1 <<  1)
-#define DMA_CTL_FIFO_EN   (1 <<  0)
-
-/* RISC instructions */
-#define RISC_WRITE        (0x01 << 28)
-#define RISC_JUMP         (0x07 << 28)
-#define RISC_SYNC         (0x08 << 28)
-
-/* RISC bits */
-#define RISC_WR_SOL       (1 << 27)
-#define RISC_WR_EOL       (1 << 26)
-#define RISC_IRQ          (1 << 24)
-#define RISC_SYNC_RESYNC  (1 << 15)
-#define RISC_SYNC_FM1     0x06
-#define RISC_SYNC_VRO     0x0c
-
-#define HWBASE_AD (448000)
-
-/* -------------------------------------------------------------- */
-
-struct btaudio {
-       /* linked list */
-       struct btaudio *next;
-
-       /* device info */
-       int            dsp_digital;
-       int            dsp_analog;
-       int            mixer_dev;
-       struct pci_dev *pci;
-       unsigned int   irq;
-       unsigned long  mem;
-       unsigned long  __iomem *mmio;
-
-       /* locking */
-       int            users;
-       struct mutex lock;
-
-       /* risc instructions */
-       unsigned int   risc_size;
-       unsigned long  *risc_cpu;
-       dma_addr_t     risc_dma;
-
-       /* audio data */
-       unsigned int   buf_size;
-       unsigned char  *buf_cpu;
-       dma_addr_t     buf_dma;
-
-       /* buffer setup */
-       int line_bytes;
-       int line_count;
-       int block_bytes;
-       int block_count;
-
-       /* read fifo management */
-       int recording;
-       int dma_block;
-       int read_offset;
-       int read_count;
-       wait_queue_head_t readq;
-
-       /* settings */
-       int gain[3];
-       int source;
-       int bits;
-       int decimation;
-       int mixcount;
-       int sampleshift;
-       int channels;
-       int analog;
-       int rate;
-};
-
-struct cardinfo {
-       char *name;
-       int rate;
-};
-
-static struct btaudio *btaudios;
-static unsigned int debug;
-static unsigned int irq_debug;
-
-/* -------------------------------------------------------------- */
-
-#define BUF_DEFAULT 128*1024
-#define BUF_MIN         8192
-
-static int alloc_buffer(struct btaudio *bta)
-{
-       if (NULL == bta->buf_cpu) {
-               for (bta->buf_size = BUF_DEFAULT; bta->buf_size >= BUF_MIN;
-                    bta->buf_size = bta->buf_size >> 1) {
-                       bta->buf_cpu = pci_alloc_consistent
-                               (bta->pci, bta->buf_size, &bta->buf_dma);
-                       if (NULL != bta->buf_cpu)
-                               break;
-               }
-               if (NULL == bta->buf_cpu)
-                       return -ENOMEM;
-               memset(bta->buf_cpu,0,bta->buf_size);
-       }
-       if (NULL == bta->risc_cpu) {
-               bta->risc_size = PAGE_SIZE;
-               bta->risc_cpu = pci_alloc_consistent
-                       (bta->pci, bta->risc_size, &bta->risc_dma);
-               if (NULL == bta->risc_cpu) {
-                       pci_free_consistent(bta->pci, bta->buf_size, bta->buf_cpu, bta->buf_dma);
-                       bta->buf_cpu = NULL;
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-static void free_buffer(struct btaudio *bta)
-{
-       if (NULL != bta->buf_cpu) {
-               pci_free_consistent(bta->pci, bta->buf_size,
-                                   bta->buf_cpu, bta->buf_dma);
-               bta->buf_cpu = NULL;
-       }
-       if (NULL != bta->risc_cpu) {
-               pci_free_consistent(bta->pci, bta->risc_size,
-                                   bta->risc_cpu, bta->risc_dma);
-               bta->risc_cpu = NULL;
-       }
-}
-
-static int make_risc(struct btaudio *bta)
-{
-       int rp, bp, line, block;
-       unsigned long risc;
-
-       bta->block_bytes = bta->buf_size >> 4;
-       bta->block_count = 1 << 4;
-       bta->line_bytes  = bta->block_bytes;
-       bta->line_count  = bta->block_count;
-       while (bta->line_bytes > 4095) {
-               bta->line_bytes >>= 1;
-               bta->line_count <<= 1;
-       }
-       if (bta->line_count > 255)
-               return -EINVAL;
-       if (debug)
-               printk(KERN_DEBUG
-                      "btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n",
-                      bta->buf_size,bta->block_bytes,bta->block_count,
-                      bta->line_bytes,bta->line_count);
-        rp = 0; bp = 0;
-       block = 0;
-       bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_FM1);
-       bta->risc_cpu[rp++] = cpu_to_le32(0);
-       for (line = 0; line < bta->line_count; line++) {
-               risc  = RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL;
-               risc |= bta->line_bytes;
-               if (0 == (bp & (bta->block_bytes-1))) {
-                       risc |= RISC_IRQ;
-                       risc |= (block  & 0x0f) << 16;
-                       risc |= (~block & 0x0f) << 20;
-                       block++;
-               }
-               bta->risc_cpu[rp++] = cpu_to_le32(risc);
-               bta->risc_cpu[rp++] = cpu_to_le32(bta->buf_dma + bp);
-               bp += bta->line_bytes;
-       }
-       bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_VRO);
-       bta->risc_cpu[rp++] = cpu_to_le32(0);
-       bta->risc_cpu[rp++] = cpu_to_le32(RISC_JUMP); 
-       bta->risc_cpu[rp++] = cpu_to_le32(bta->risc_dma);
-       return 0;
-}
-
-static int start_recording(struct btaudio *bta)
-{
-       int ret;
-
-       if (0 != (ret = alloc_buffer(bta)))
-               return ret;
-       if (0 != (ret = make_risc(bta)))
-               return ret;
-
-       btwrite(bta->risc_dma, REG_RISC_STRT_ADD);
-       btwrite((bta->line_count << 16) | bta->line_bytes,
-               REG_PACKET_LEN);
-       btwrite(IRQ_BTAUDIO, REG_INT_MASK);
-       if (bta->analog) {
-               btwrite(DMA_CTL_ACAP_EN |
-                       DMA_CTL_RISC_EN |
-                       DMA_CTL_FIFO_EN |
-                       DMA_CTL_DA_ES2  |
-                       ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
-                       (bta->gain[bta->source] << 28) |
-                       (bta->source            << 24) |
-                       (bta->decimation        <<  8),
-                       REG_GPIO_DMA_CTL);
-       } else {
-               btwrite(DMA_CTL_ACAP_EN |
-                       DMA_CTL_RISC_EN |
-                       DMA_CTL_FIFO_EN |
-                       DMA_CTL_DA_ES2  |
-                       DMA_CTL_A_PWRDN |
-                       (1 << 6)   |
-                       ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |
-                       (bta->gain[bta->source] << 28) |
-                       (bta->source            << 24) |
-                       (bta->decimation        <<  8),
-                       REG_GPIO_DMA_CTL);
-       }
-       bta->dma_block = 0;
-       bta->read_offset = 0;
-       bta->read_count = 0;
-       bta->recording = 1;
-       if (debug)
-               printk(KERN_DEBUG "btaudio: recording started\n");
-       return 0;
-}
-
-static void stop_recording(struct btaudio *bta)
-{
-        btand(~15, REG_GPIO_DMA_CTL);
-       bta->recording = 0;
-       if (debug)
-               printk(KERN_DEBUG "btaudio: recording stopped\n");
-}
-
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_mixer_open(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct btaudio *bta;
-
-       for (bta = btaudios; bta != NULL; bta = bta->next)
-               if (bta->mixer_dev == minor)
-                       break;
-       if (NULL == bta)
-               return -ENODEV;
-
-       if (debug)
-               printk("btaudio: open mixer [%d]\n",minor);
-       file->private_data = bta;
-       return 0;
-}
-
-static int btaudio_mixer_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
-                              unsigned int cmd, unsigned long arg)
-{
-       struct btaudio *bta = file->private_data;
-       int ret,val=0,i=0;
-       void __user *argp = (void __user *)arg;
-
-       if (cmd == SOUND_MIXER_INFO) {
-               mixer_info info;
-               memset(&info,0,sizeof(info));
-                strlcpy(info.id,"bt878",sizeof(info.id));
-                strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
-                info.modify_counter = bta->mixcount;
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-               return 0;
-       }
-       if (cmd == SOUND_OLD_MIXER_INFO) {
-               _old_mixer_info info;
-               memset(&info,0,sizeof(info));
-                strlcpy(info.id, "bt878", sizeof(info.id));
-                strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-               return 0;
-       }
-       if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, (int __user *)argp);
-
-       /* read */
-       if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-               if (get_user(val, (int __user *)argp))
-                       return -EFAULT;
-
-       switch (cmd) {
-       case MIXER_READ(SOUND_MIXER_CAPS):
-               ret = SOUND_CAP_EXCL_INPUT;
-               break;
-       case MIXER_READ(SOUND_MIXER_STEREODEVS):
-               ret = 0;
-               break;
-       case MIXER_READ(SOUND_MIXER_RECMASK):
-       case MIXER_READ(SOUND_MIXER_DEVMASK):
-               ret = SOUND_MASK_LINE1|SOUND_MASK_LINE2|SOUND_MASK_LINE3;
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_RECSRC):
-               if (val & SOUND_MASK_LINE1 && bta->source != 0)
-                       bta->source = 0;
-               else if (val & SOUND_MASK_LINE2 && bta->source != 1)
-                       bta->source = 1;
-               else if (val & SOUND_MASK_LINE3 && bta->source != 2)
-                       bta->source = 2;
-               btaor((bta->gain[bta->source] << 28) |
-                     (bta->source            << 24),
-                     0x0cffffff, REG_GPIO_DMA_CTL);
-       case MIXER_READ(SOUND_MIXER_RECSRC):
-               switch (bta->source) {
-               case 0:  ret = SOUND_MASK_LINE1; break;
-               case 1:  ret = SOUND_MASK_LINE2; break;
-               case 2:  ret = SOUND_MASK_LINE3; break;
-               default: ret = 0;
-               }
-               break;
-
-       case MIXER_WRITE(SOUND_MIXER_LINE1):
-       case MIXER_WRITE(SOUND_MIXER_LINE2):
-       case MIXER_WRITE(SOUND_MIXER_LINE3):
-               if (MIXER_WRITE(SOUND_MIXER_LINE1) == cmd)
-                       i = 0;
-               if (MIXER_WRITE(SOUND_MIXER_LINE2) == cmd)
-                       i = 1;
-               if (MIXER_WRITE(SOUND_MIXER_LINE3) == cmd)
-                       i = 2;
-               bta->gain[i] = (val & 0xff) * 15 / 100;
-               if (bta->gain[i] > 15) bta->gain[i] = 15;
-               if (bta->gain[i] <  0) bta->gain[i] =  0;
-               if (i == bta->source)
-                       btaor((bta->gain[bta->source]<<28),
-                             0x0fffffff, REG_GPIO_DMA_CTL);
-               ret  = bta->gain[i] * 100 / 15;
-               ret |= ret << 8;
-               break;
-
-       case MIXER_READ(SOUND_MIXER_LINE1):
-       case MIXER_READ(SOUND_MIXER_LINE2):
-       case MIXER_READ(SOUND_MIXER_LINE3):
-               if (MIXER_READ(SOUND_MIXER_LINE1) == cmd)
-                       i = 0;
-               if (MIXER_READ(SOUND_MIXER_LINE2) == cmd)
-                       i = 1;
-               if (MIXER_READ(SOUND_MIXER_LINE3) == cmd)
-                       i = 2;
-               ret  = bta->gain[i] * 100 / 15;
-               ret |= ret << 8;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       if (put_user(ret, (int __user *)argp))
-               return -EFAULT;
-       return 0;
-}
-
-static const struct file_operations btaudio_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = btaudio_mixer_open,
-       .release        = btaudio_mixer_release,
-       .ioctl          = btaudio_mixer_ioctl,
-};
-
-/* -------------------------------------------------------------- */
-
-static int btaudio_dsp_open(struct inode *inode, struct file *file,
-                           struct btaudio *bta, int analog)
-{
-       mutex_lock(&bta->lock);
-       if (bta->users)
-               goto busy;
-       bta->users++;
-       file->private_data = bta;
-
-       bta->analog = analog;
-       bta->dma_block = 0;
-       bta->read_offset = 0;
-       bta->read_count = 0;
-       bta->sampleshift = 0;
-
-       mutex_unlock(&bta->lock);
-       return 0;
-
- busy:
-       mutex_unlock(&bta->lock);
-       return -EBUSY;
-}
-
-static int btaudio_dsp_open_digital(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct btaudio *bta;
-
-       for (bta = btaudios; bta != NULL; bta = bta->next)
-               if (bta->dsp_digital == minor)
-                       break;
-       if (NULL == bta)
-               return -ENODEV;
-       
-       if (debug)
-               printk("btaudio: open digital dsp [%d]\n",minor);
-       return btaudio_dsp_open(inode,file,bta,0);
-}
-
-static int btaudio_dsp_open_analog(struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct btaudio *bta;
-
-       for (bta = btaudios; bta != NULL; bta = bta->next)
-               if (bta->dsp_analog == minor)
-                       break;
-       if (NULL == bta)
-               return -ENODEV;
-
-       if (debug)
-               printk("btaudio: open analog dsp [%d]\n",minor);
-       return btaudio_dsp_open(inode,file,bta,1);
-}
-
-static int btaudio_dsp_release(struct inode *inode, struct file *file)
-{
-       struct btaudio *bta = file->private_data;
-
-       mutex_lock(&bta->lock);
-       if (bta->recording)
-               stop_recording(bta);
-       bta->users--;
-       mutex_unlock(&bta->lock);
-       return 0;
-}
-
-static ssize_t btaudio_dsp_read(struct file *file, char __user *buffer,
-                               size_t swcount, loff_t *ppos)
-{
-       struct btaudio *bta = file->private_data;
-       int hwcount = swcount << bta->sampleshift;
-       int nsrc, ndst, err, ret = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&bta->readq, &wait);
-       mutex_lock(&bta->lock);
-       while (swcount > 0) {
-               if (0 == bta->read_count) {
-                       if (!bta->recording) {
-                               if (0 != (err = start_recording(bta))) {
-                                       if (0 == ret)
-                                               ret = err;
-                                       break;
-                               }
-                       }
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (0 == ret)
-                                       ret = -EAGAIN;
-                               break;
-                       }
-                       mutex_unlock(&bta->lock);
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule();
-                       mutex_lock(&bta->lock);
-                       if(signal_pending(current)) {
-                               if (0 == ret)
-                                       ret = -EINTR;
-                               break;
-                       }
-               }
-               nsrc = (bta->read_count < hwcount) ? bta->read_count : hwcount;
-               if (nsrc > bta->buf_size - bta->read_offset)
-                       nsrc = bta->buf_size - bta->read_offset;
-               ndst = nsrc >> bta->sampleshift;
-               
-               if ((bta->analog  && 0 == bta->sampleshift) ||
-                   (!bta->analog && 2 == bta->channels)) {
-                       /* just copy */
-                       if (copy_to_user(buffer + ret, bta->buf_cpu + bta->read_offset, nsrc)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-
-               } else if (!bta->analog) {
-                       /* stereo => mono (digital audio) */
-                       __s16 *src = (__s16*)(bta->buf_cpu + bta->read_offset);
-                       __s16 __user *dst = (__s16 __user *)(buffer + ret);
-                       __s16 avg;
-                       int n = ndst>>1;
-                       if (!access_ok(VERIFY_WRITE, dst, ndst)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       for (; n; n--, dst++) {
-                               avg  = (__s16)le16_to_cpu(*src) / 2; src++;
-                               avg += (__s16)le16_to_cpu(*src) / 2; src++;
-                               __put_user(cpu_to_le16(avg),dst);
-                       }
-
-               } else if (8 == bta->bits) {
-                       /* copy + byte downsampling (audio A/D) */
-                       __u8 *src = bta->buf_cpu + bta->read_offset;
-                       __u8 __user *dst = buffer + ret;
-                       int n = ndst;
-                       if (!access_ok(VERIFY_WRITE, dst, ndst)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       for (; n; n--, src += (1 << bta->sampleshift), dst++)
-                               __put_user(*src, dst);
-
-               } else {
-                       /* copy + word downsampling (audio A/D) */
-                       __u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);
-                       __u16 __user *dst = (__u16 __user *)(buffer + ret);
-                       int n = ndst>>1;
-                       if (!access_ok(VERIFY_WRITE,dst,ndst)) {
-                               if (0 == ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-                       for (; n; n--, src += (1 << bta->sampleshift), dst++)
-                               __put_user(*src, dst);
-               }
-
-               ret     += ndst;
-               swcount -= ndst;
-               hwcount -= nsrc;
-               bta->read_count  -= nsrc;
-               bta->read_offset += nsrc;
-               if (bta->read_offset == bta->buf_size)
-                       bta->read_offset = 0;
-       }
-       mutex_unlock(&bta->lock);
-       remove_wait_queue(&bta->readq, &wait);
-       current->state = TASK_RUNNING;
-       return ret;
-}
-
-static ssize_t btaudio_dsp_write(struct file *file, const char __user *buffer,
-                                size_t count, loff_t *ppos)
-{
-       return -EINVAL;
-}
-
-static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg)
-{
-       struct btaudio *bta = file->private_data;
-       int s, i, ret, val = 0;
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       
-        switch (cmd) {
-        case OSS_GETVERSION:
-                return put_user(SOUND_VERSION, p);
-        case SNDCTL_DSP_GETCAPS:
-               return 0;
-
-        case SNDCTL_DSP_SPEED:
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (bta->analog) {
-                       for (s = 0; s < 16; s++)
-                               if (val << s >= HWBASE_AD*4/15)
-                                       break;
-                       for (i = 15; i >= 5; i--)
-                               if (val << s <= HWBASE_AD*4/i)
-                                       break;
-                       bta->sampleshift = s;
-                       bta->decimation  = i;
-                       if (debug)
-                               printk(KERN_DEBUG "btaudio: rate: req=%d  "
-                                      "dec=%d shift=%d hwrate=%d swrate=%d\n",
-                                      val,i,s,(HWBASE_AD*4/i),(HWBASE_AD*4/i)>>s);
-               } else {
-                       bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       bta->decimation  = 0;
-               }
-               if (bta->recording) {
-                       mutex_lock(&bta->lock);
-                       stop_recording(bta);
-                       start_recording(bta);
-                       mutex_unlock(&bta->lock);
-               }
-               /* fall through */
-        case SOUND_PCM_READ_RATE:
-               if (bta->analog) {
-                       return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, p);
-               } else {
-                       return put_user(bta->rate, p);
-               }
-
-        case SNDCTL_DSP_STEREO:
-               if (!bta->analog) {
-                       if (get_user(val, p))
-                               return -EFAULT;
-                       bta->channels    = (val > 0) ? 2 : 1;
-                       bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       if (debug)
-                               printk(KERN_INFO
-                                      "btaudio: stereo=%d channels=%d\n",
-                                      val,bta->channels);
-               } else {
-                       if (val == 1)
-                               return -EFAULT;
-                       else {
-                               bta->channels = 1;
-                               if (debug)
-                                       printk(KERN_INFO
-                                              "btaudio: stereo=0 channels=1\n");
-                       }
-               }
-               return put_user((bta->channels)-1, p);
-
-        case SNDCTL_DSP_CHANNELS:
-               if (!bta->analog) {
-                       if (get_user(val, p))
-                               return -EFAULT;
-                       bta->channels    = (val > 1) ? 2 : 1;
-                       bta->sampleshift = (bta->channels == 2) ? 0 : 1;
-                       if (debug)
-                               printk(KERN_DEBUG
-                                      "btaudio: val=%d channels=%d\n",
-                                      val,bta->channels);
-               }
-               /* fall through */
-        case SOUND_PCM_READ_CHANNELS:
-               return put_user(bta->channels, p);
-               
-        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-               if (bta->analog)
-                       return put_user(AFMT_S16_LE|AFMT_S8, p);
-               else
-                       return put_user(AFMT_S16_LE, p);
-
-        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-               if (get_user(val, p))
-                       return -EFAULT;
-                if (val != AFMT_QUERY) {
-                       if (bta->analog)
-                               bta->bits = (val == AFMT_S8) ? 8 : 16;
-                       else
-                               bta->bits = 16;
-                       if (bta->recording) {
-                               mutex_lock(&bta->lock);
-                               stop_recording(bta);
-                               start_recording(bta);
-                               mutex_unlock(&bta->lock);
-                       }
-               }
-               if (debug)
-                       printk(KERN_DEBUG "btaudio: fmt: bits=%d\n",bta->bits);
-                return put_user((bta->bits==16) ? AFMT_S16_LE : AFMT_S8,
-                               p);
-               break;
-        case SOUND_PCM_READ_BITS:
-               return put_user(bta->bits, p);
-
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_RESET:
-               if (bta->recording) {
-                       mutex_lock(&bta->lock);
-                       stop_recording(bta);
-                       mutex_unlock(&bta->lock);
-               }
-               return 0;
-        case SNDCTL_DSP_GETBLKSIZE:
-               if (!bta->recording) {
-                       if (0 != (ret = alloc_buffer(bta)))
-                               return ret;
-                       if (0 != (ret = make_risc(bta)))
-                               return ret;
-               }
-               return put_user(bta->block_bytes>>bta->sampleshift,p);
-
-        case SNDCTL_DSP_SYNC:
-               /* NOP */
-               return 0;
-       case SNDCTL_DSP_GETISPACE:
-       {
-               audio_buf_info info;
-               if (!bta->recording)
-                       return -EINVAL;
-               info.fragsize = bta->block_bytes>>bta->sampleshift;
-               info.fragstotal = bta->block_count;
-               info.bytes = bta->read_count;
-               info.fragments = info.bytes / info.fragsize;
-               if (debug)
-                       printk(KERN_DEBUG "btaudio: SNDCTL_DSP_GETISPACE "
-                              "returns %d/%d/%d/%d\n",
-                              info.fragsize, info.fragstotal,
-                              info.bytes, info.fragments);
-               if (copy_to_user(argp, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-       }
-#if 0 /* TODO */
-        case SNDCTL_DSP_GETTRIGGER:
-        case SNDCTL_DSP_SETTRIGGER:
-        case SNDCTL_DSP_SETFRAGMENT:
-#endif
-       default:
-               return -EINVAL;
-       }
-}
-
-static unsigned int btaudio_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct btaudio *bta = file->private_data;
-       unsigned int mask = 0;
-
-       poll_wait(file, &bta->readq, wait);
-
-       if (0 != bta->read_count)
-               mask |= (POLLIN | POLLRDNORM);
-
-       return mask;
-}
-
-static const struct file_operations btaudio_digital_dsp_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = btaudio_dsp_open_digital,
-       .release        = btaudio_dsp_release,
-       .read           = btaudio_dsp_read,
-       .write          = btaudio_dsp_write,
-       .ioctl          = btaudio_dsp_ioctl,
-       .poll           = btaudio_dsp_poll,
-};
-
-static const struct file_operations btaudio_analog_dsp_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = btaudio_dsp_open_analog,
-       .release        = btaudio_dsp_release,
-       .read           = btaudio_dsp_read,
-       .write          = btaudio_dsp_write,
-       .ioctl          = btaudio_dsp_ioctl,
-       .poll           = btaudio_dsp_poll,
-};
-
-/* -------------------------------------------------------------- */
-
-static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "",
-                           "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
-                           "RIPERR", "PABORT", "OCERR", "SCERR" };
-
-static irqreturn_t btaudio_irq(int irq, void *dev_id)
-{
-       int count = 0;
-       u32 stat,astat;
-       struct btaudio *bta = dev_id;
-       int handled = 0;
-
-       for (;;) {
-               count++;
-               stat  = btread(REG_INT_STAT);
-               astat = stat & btread(REG_INT_MASK);
-               if (!astat)
-                       return IRQ_RETVAL(handled);
-               handled = 1;
-               btwrite(astat,REG_INT_STAT);
-
-               if (irq_debug) {
-                       int i;
-                       printk(KERN_DEBUG "btaudio: irq loop=%d risc=%x, bits:",
-                              count, stat>>28);
-                       for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
-                               if (stat & (1 << i))
-                                       printk(" %s",irq_name[i]);
-                               if (astat & (1 << i))
-                                       printk("*");
-                       }
-                       printk("\n");
-               }
-               if (stat & IRQ_RISCI) {
-                       int blocks;
-                       blocks = (stat >> 28) - bta->dma_block;
-                       if (blocks < 0)
-                               blocks += bta->block_count;
-                       bta->dma_block = stat >> 28;
-                       if (bta->read_count + 2*bta->block_bytes > bta->buf_size) {
-                               stop_recording(bta);
-                               printk(KERN_INFO "btaudio: buffer overrun\n");
-                       }
-                       if (blocks > 0) {
-                               bta->read_count += blocks * bta->block_bytes;
-                               wake_up_interruptible(&bta->readq);
-                       }
-               }
-               if (count > 10) {
-                       printk(KERN_WARNING
-                              "btaudio: Oops - irq mask cleared\n");
-                       btwrite(0, REG_INT_MASK);
-               }
-       }
-       return IRQ_NONE;
-}
-
-/* -------------------------------------------------------------- */
-
-static unsigned int dsp1 = -1;
-static unsigned int dsp2 = -1;
-static unsigned int mixer = -1;
-static int latency = -1;
-static int digital = 1;
-static int analog = 1;
-static int rate;
-
-#define BTA_OSPREY200 1
-
-static struct cardinfo cards[] = {
-       [0] = {
-               .name   = "default",
-               .rate   = 32000,
-       },
-       [BTA_OSPREY200] = {
-               .name   = "Osprey 200",
-               .rate   = 44100,
-       },
-};
-
-static int __devinit btaudio_probe(struct pci_dev *pci_dev,
-                                  const struct pci_device_id *pci_id)
-{
-       struct btaudio *bta;
-       struct cardinfo *card = &cards[pci_id->driver_data];
-       unsigned char revision,lat;
-       int rc = -EBUSY;
-
-       if (pci_enable_device(pci_dev))
-               return -EIO;
-       if (!request_mem_region(pci_resource_start(pci_dev,0),
-                               pci_resource_len(pci_dev,0),
-                               "btaudio")) {
-               return -EBUSY;
-       }
-
-       bta = kzalloc(sizeof(*bta),GFP_ATOMIC);
-       if (!bta) {
-               rc = -ENOMEM;
-               goto fail0;
-       }
-
-       bta->pci  = pci_dev;
-       bta->irq  = pci_dev->irq;
-       bta->mem  = pci_resource_start(pci_dev,0);
-       bta->mmio = ioremap(pci_resource_start(pci_dev,0),
-                           pci_resource_len(pci_dev,0));
-
-       bta->source     = 1;
-       bta->bits       = 8;
-       bta->channels   = 1;
-       if (bta->analog) {
-               bta->decimation  = 15;
-       } else {
-               bta->decimation  = 0;
-               bta->sampleshift = 1;
-       }
-
-       /* sample rate */
-       bta->rate = card->rate;
-       if (rate)
-               bta->rate = rate;
-       
-       mutex_init(&bta->lock);
-        init_waitqueue_head(&bta->readq);
-
-       if (-1 != latency) {
-               printk(KERN_INFO "btaudio: setting pci latency timer to %d\n",
-                      latency);
-               pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
-       }
-        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat);
-        printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",
-              pci_dev->device,revision,pci_dev->bus->number,
-              PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));
-        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
-              bta->irq, lat, bta->mem);
-       printk("btaudio: using card config \"%s\"\n", card->name);
-
-       /* init hw */
-        btwrite(0, REG_GPIO_DMA_CTL);
-        btwrite(0, REG_INT_MASK);
-        btwrite(~0U, REG_INT_STAT);
-       pci_set_master(pci_dev);
-
-       if ((rc = request_irq(bta->irq, btaudio_irq, IRQF_SHARED|IRQF_DISABLED,
-                             "btaudio",(void *)bta)) < 0) {
-               printk(KERN_WARNING
-                      "btaudio: can't request irq (rc=%d)\n",rc);
-               goto fail1;
-       }
-
-       /* register devices */
-       if (digital) {
-               rc = bta->dsp_digital =
-                       register_sound_dsp(&btaudio_digital_dsp_fops,dsp1);
-               if (rc < 0) {
-                       printk(KERN_WARNING
-                              "btaudio: can't register digital dsp (rc=%d)\n",rc);
-                       goto fail2;
-               }
-               printk(KERN_INFO "btaudio: registered device dsp%d [digital]\n",
-                      bta->dsp_digital >> 4);
-       }
-       if (analog) {
-               rc = bta->dsp_analog =
-                       register_sound_dsp(&btaudio_analog_dsp_fops,dsp2);
-               if (rc < 0) {
-                       printk(KERN_WARNING
-                              "btaudio: can't register analog dsp (rc=%d)\n",rc);
-                       goto fail3;
-               }
-               printk(KERN_INFO "btaudio: registered device dsp%d [analog]\n",
-                      bta->dsp_analog >> 4);
-               rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer);
-               if (rc < 0) {
-                       printk(KERN_WARNING
-                              "btaudio: can't register mixer (rc=%d)\n",rc);
-                       goto fail4;
-               }
-               printk(KERN_INFO "btaudio: registered device mixer%d\n",
-                      bta->mixer_dev >> 4);
-       }
-
-       /* hook into linked list */
-       bta->next = btaudios;
-       btaudios = bta;
-
-       pci_set_drvdata(pci_dev,bta);
-        return 0;
-
- fail4:
-       unregister_sound_dsp(bta->dsp_analog);
- fail3:
-       if (digital)
-               unregister_sound_dsp(bta->dsp_digital);
- fail2:
-        free_irq(bta->irq,bta);        
- fail1:
-       iounmap(bta->mmio);
-       kfree(bta);
- fail0:
-       release_mem_region(pci_resource_start(pci_dev,0),
-                          pci_resource_len(pci_dev,0));
-       return rc;
-}
-
-static void __devexit btaudio_remove(struct pci_dev *pci_dev)
-{
-       struct btaudio *bta = pci_get_drvdata(pci_dev);
-       struct btaudio *walk;
-
-       /* turn off all DMA / IRQs */
-        btand(~15, REG_GPIO_DMA_CTL);
-        btwrite(0, REG_INT_MASK);
-        btwrite(~0U, REG_INT_STAT);
-
-       /* unregister devices */
-       if (digital) {
-               unregister_sound_dsp(bta->dsp_digital);
-       }
-       if (analog) {
-               unregister_sound_dsp(bta->dsp_analog);
-               unregister_sound_mixer(bta->mixer_dev);
-       }
-
-       /* free resources */
-       free_buffer(bta);
-        free_irq(bta->irq,bta);
-       release_mem_region(pci_resource_start(pci_dev,0),
-                          pci_resource_len(pci_dev,0));
-       iounmap(bta->mmio);
-
-       /* remove from linked list */
-       if (bta == btaudios) {
-               btaudios = NULL;
-       } else {
-               for (walk = btaudios; walk->next != bta; walk = walk->next)
-                       ; /* if (NULL == walk->next) BUG(); */
-               walk->next = bta->next;
-       }
-
-       pci_set_drvdata(pci_dev, NULL);
-       kfree(bta);
-       return;
-}
-
-/* -------------------------------------------------------------- */
-
-static struct pci_device_id btaudio_pci_tbl[] = {
-        {
-               .vendor         = PCI_VENDOR_ID_BROOKTREE,
-               .device         = 0x0878,
-               .subvendor      = 0x0070,
-               .subdevice      = 0xff01,
-               .driver_data    = BTA_OSPREY200,
-       },{
-               .vendor         = PCI_VENDOR_ID_BROOKTREE,
-               .device         = 0x0878,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-       },{
-               .vendor         = PCI_VENDOR_ID_BROOKTREE,
-               .device         = 0x0878,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-        },{
-               /* --- end of list --- */
-       }
-};
-
-static struct pci_driver btaudio_pci_driver = {
-        .name          = "btaudio",
-        .id_table      = btaudio_pci_tbl,
-        .probe         = btaudio_probe,
-        .remove                =  __devexit_p(btaudio_remove),
-};
-
-static int btaudio_init_module(void)
-{
-       printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",
-              digital ? "digital" : "",
-              analog && digital ? "+" : "",
-              analog ? "analog" : "");
-       return pci_register_driver(&btaudio_pci_driver);
-}
-
-static void btaudio_cleanup_module(void)
-{
-       pci_unregister_driver(&btaudio_pci_driver);
-       return;
-}
-
-module_init(btaudio_init_module);
-module_exit(btaudio_cleanup_module);
-
-module_param(dsp1, int, S_IRUGO);
-module_param(dsp2, int, S_IRUGO);
-module_param(mixer, int, S_IRUGO);
-module_param(debug, int, S_IRUGO | S_IWUSR);
-module_param(irq_debug, int, S_IRUGO | S_IWUSR);
-module_param(digital, int, S_IRUGO);
-module_param(analog, int, S_IRUGO);
-module_param(rate, int, S_IRUGO);
-module_param(latency, int, S_IRUGO);
-MODULE_PARM_DESC(latency,"pci latency timer");
-
-MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);
-MODULE_DESCRIPTION("bt878 audio dma driver");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c
deleted file mode 100644 (file)
index de40e21..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- *     cs4232.c
- *
- * The low level driver for Crystal CS4232 based cards. The CS4232 is
- * a PnP compatible chip which contains a CS4231A codec, SB emulation,
- * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM 
- * interfaces. This is just a temporary driver until full PnP support
- * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
- * supported. Other interfaces are left uninitialized.
- *
- * ifdef ...WAVEFRONT...
- * 
- *   Support is provided for initializing the WaveFront synth
- *   interface as well, which is logical device #4. Note that if
- *   you have a Tropez+ card, you probably don't need to setup
- *   the CS4232-supported MIDI interface, since it corresponds to
- *   the internal 26-pin header that's hard to access. Using this
- *   requires an additional IRQ, a resource none too plentiful in
- *   this environment. Just don't set module parameters mpuio and
- *   mpuirq, and the MIDI port will be left uninitialized. You can
- *   still use the ICS2115 hosted MIDI interface which corresponds
- *   to the 9-pin D connector on the back of the card.
- *
- * endif  ...WAVEFRONT...
- *
- * Supported chips are:
- *      CS4232
- *      CS4236
- *      CS4236B
- *
- * Note: You will need a PnP config setup to initialise some CS4232 boards
- * anyway.
- *
- * Changes
- *      John Rood               Added Bose Sound System Support.
- *      Toshio Spoor
- *     Alan Cox                Modularisation, Basic cleanups.
- *      Paul Barton-Davis      Separated MPU configuration, added
- *                                       Tropez+ (WaveFront) support
- *     Christoph Hellwig       Adapted to module_init/module_exit,
- *                                     simple cleanups
- *     Arnaldo C. de Melo      got rid of attach_uart401
- *     Bartlomiej Zolnierkiewicz
- *                             Added some __init/__initdata/__exit
- *     Marcus Meissner         Added ISA PnP support.
- */
-
-#include <linux/pnp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#define KEY_PORT       0x279   /* Same as LPT1 status port */
-#define CSN_NUM                0x99    /* Just a random number */
-#define INDEX_ADDRESS   0x00    /* (R0) Index Address Register */
-#define INDEX_DATA      0x01    /* (R1) Indexed Data Register */
-#define PIN_CONTROL     0x0a    /* (I10) Pin Control */
-#define ENABLE_PINS     0xc0    /* XCTRL0/XCTRL1 enable */
-
-static void CS_OUT(unsigned char a)
-{
-       outb(a, KEY_PORT);
-}
-
-#define CS_OUT2(a, b)          {CS_OUT(a);CS_OUT(b);}
-#define CS_OUT3(a, b, c)       {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
-
-static int __initdata bss       = 0;
-static int mpu_base, mpu_irq;
-static int synth_base, synth_irq;
-static int mpu_detected;
-
-static int probe_cs4232_mpu(struct address_info *hw_config)
-{
-       /*
-        *      Just write down the config values.
-        */
-
-       mpu_base = hw_config->io_base;
-       mpu_irq = hw_config->irq;
-
-       return 1;
-}
-
-static unsigned char crystal_key[] =   /* A 32 byte magic key sequence */
-{
-       0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
-       0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
-       0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
-       0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
-};
-
-static void sleep(unsigned howlong)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(howlong);
-}
-
-static void enable_xctrl(int baseio)
-{
-        unsigned char regd;
-                
-        /*
-         * Some IBM Aptiva's have the Bose Sound System. By default
-         * the Bose Amplifier is disabled. The amplifier will be 
-         * activated, by setting the XCTRL0 and XCTRL1 bits.
-         * Volume of the monitor bose speakers/woofer, can then
-         * be set by changing the PCM volume.
-         *
-         */
-                
-        printk("cs4232: enabling Bose Sound System Amplifier.\n");
-        
-        /* Switch to Pin Control Address */                   
-        regd = inb(baseio + INDEX_ADDRESS) & 0xe0;
-        outb(((unsigned char) (PIN_CONTROL | regd)), baseio + INDEX_ADDRESS );
-        
-        /* Activate the XCTRL0 and XCTRL1 Pins */
-        regd = inb(baseio + INDEX_DATA);
-        outb(((unsigned char) (ENABLE_PINS | regd)), baseio + INDEX_DATA );
-}
-
-static int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured)
-{
-       int i, n;
-       int base = hw_config->io_base, irq = hw_config->irq;
-       int dma1 = hw_config->dma, dma2 = hw_config->dma2;
-       struct resource *ports;
-
-       if (base == -1 || irq == -1 || dma1 == -1) {
-               printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");
-               return 0;
-       }
-
-       /*
-        * Verify that the I/O port range is free.
-        */
-
-       ports = request_region(base, 4, "ad1848");
-       if (!ports) {
-               printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base);
-               return 0;
-       }
-       if (ad1848_detect(ports, NULL, hw_config->osp)) {
-               goto got_it;    /* The card is already active */
-       }
-       if (isapnp_configured) {
-               printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n");
-               goto fail;
-       }
-
-       /*
-        * This version of the driver doesn't use the PnP method when configuring
-        * the card but a simplified method defined by Crystal. This means that
-        * just one CS4232 compatible device can exist on the system. Also this
-        * method conflicts with possible PnP support in the OS. For this reason 
-        * driver is just a temporary kludge.
-        *
-        * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;)
-        */
-
-       /*
-        * Repeat initialization few times since it doesn't always succeed in
-        * first time.
-        */
-
-       for (n = 0; n < 4; n++)
-       {       
-               /*
-                *      Wake up the card by sending a 32 byte Crystal key to the key port.
-                */
-               
-               for (i = 0; i < 32; i++)
-                       CS_OUT(crystal_key[i]);
-
-               sleep(HZ / 10);
-
-               /*
-                *      Now set the CSN (Card Select Number).
-                */
-
-               CS_OUT2(0x06, CSN_NUM);
-
-               /*
-                *      Then set some config bytes. First logical device 0 
-                */
-
-               CS_OUT2(0x15, 0x00);    /* Select logical device 0 (WSS/SB/FM) */
-               CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */
-
-               if (!request_region(0x388, 4, "FM"))    /* Not free */
-                       CS_OUT3(0x48, 0x00, 0x00)       /* FM base off */
-               else {
-                       release_region(0x388, 4);
-                       CS_OUT3(0x48, 0x03, 0x88);      /* FM base 0x388 */
-               }
-
-               CS_OUT3(0x42, 0x00, 0x00);      /* SB base off */
-               CS_OUT2(0x22, irq);             /* SB+WSS IRQ */
-               CS_OUT2(0x2a, dma1);            /* SB+WSS DMA */
-
-               if (dma2 != -1)
-                       CS_OUT2(0x25, dma2)     /* WSS DMA2 */
-               else
-                       CS_OUT2(0x25, 4);       /* No WSS DMA2 */
-
-               CS_OUT2(0x33, 0x01);    /* Activate logical dev 0 */
-
-               sleep(HZ / 10);
-
-               /*
-                * Initialize logical device 3 (MPU)
-                */
-
-               if (mpu_base != 0 && mpu_irq != 0)
-               {
-                       CS_OUT2(0x15, 0x03);    /* Select logical device 3 (MPU) */
-                       CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */
-                       CS_OUT2(0x22, mpu_irq); /* MPU IRQ */
-                       CS_OUT2(0x33, 0x01);    /* Activate logical dev 3 */
-               }
-
-               if(synth_base != 0)
-               {
-                   CS_OUT2 (0x15, 0x04);               /* logical device 4 (WaveFront) */
-                   CS_OUT3 (0x47, (synth_base >> 8) & 0xff,
-                            synth_base & 0xff);        /* base */
-                   CS_OUT2 (0x22, synth_irq);          /* IRQ */
-                   CS_OUT2 (0x33, 0x01);               /* Activate logical dev 4 */
-               }
-
-               /*
-                * Finally activate the chip
-                */
-               
-               CS_OUT(0x79);
-
-               sleep(HZ / 5);
-
-               /*
-                * Then try to detect the codec part of the chip
-                */
-
-               if (ad1848_detect(ports, NULL, hw_config->osp))
-                       goto got_it;
-               
-               sleep(HZ);
-       }
-fail:
-       release_region(base, 4);
-       return 0;
-
-got_it:
-       if (dma2 == -1)
-               dma2 = dma1;
-
-       hw_config->slots[0] = ad1848_init("Crystal audio controller", ports,
-                                         irq,
-                                         dma1,         /* Playback DMA */
-                                         dma2,         /* Capture DMA */
-                                         0,
-                                         hw_config->osp,
-                                         THIS_MODULE);
-
-       if (hw_config->slots[0] != -1 &&
-               audio_devs[hw_config->slots[0]]->mixer_dev!=-1)
-       {       
-               /* Assume the mixer map is as suggested in the CS4232 databook */
-               AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
-               AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
-               AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH);           /* FM synth */
-       }
-       if (mpu_base != 0 && mpu_irq != 0)
-       {
-               static struct address_info hw_config2 = {
-                       0
-               };              /* Ensure it's initialized */
-
-               hw_config2.io_base = mpu_base;
-               hw_config2.irq = mpu_irq;
-               hw_config2.dma = -1;
-               hw_config2.dma2 = -1;
-               hw_config2.always_detect = 0;
-               hw_config2.name = NULL;
-               hw_config2.driver_use_1 = 0;
-               hw_config2.driver_use_2 = 0;
-               hw_config2.card_subtype = 0;
-
-               if (probe_uart401(&hw_config2, THIS_MODULE))
-               {
-                       mpu_detected = 1;
-               }
-               else
-               {
-                       mpu_base = mpu_irq = 0;
-               }
-               hw_config->slots[1] = hw_config2.slots[1];
-       }
-       
-       if (bss)
-               enable_xctrl(base);
-
-       return 1;
-}
-
-static void __devexit unload_cs4232(struct address_info *hw_config)
-{
-       int base = hw_config->io_base, irq = hw_config->irq;
-       int dma1 = hw_config->dma, dma2 = hw_config->dma2;
-
-       if (dma2 == -1)
-               dma2 = dma1;
-
-       ad1848_unload(base,
-                     irq,
-                     dma1,     /* Playback DMA */
-                     dma2,     /* Capture DMA */
-                     0);
-
-       sound_unload_audiodev(hw_config->slots[0]);
-       if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
-       {
-               static struct address_info hw_config2 =
-               {
-                       0
-               };              /* Ensure it's initialized */
-
-               hw_config2.io_base = mpu_base;
-               hw_config2.irq = mpu_irq;
-               hw_config2.dma = -1;
-               hw_config2.dma2 = -1;
-               hw_config2.always_detect = 0;
-               hw_config2.name = NULL;
-               hw_config2.driver_use_1 = 0;
-               hw_config2.driver_use_2 = 0;
-               hw_config2.card_subtype = 0;
-               hw_config2.slots[1] = hw_config->slots[1];
-
-               unload_uart401(&hw_config2);
-       }
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata io       = -1;
-static int __initdata irq      = -1;
-static int __initdata dma      = -1;
-static int __initdata dma2     = -1;
-static int __initdata mpuio    = -1;
-static int __initdata mpuirq   = -1;
-static int __initdata synthio  = -1;
-static int __initdata synthirq = -1;
-static int __initdata isapnp   = 1;
-
-static unsigned int cs4232_devices;
-
-MODULE_DESCRIPTION("CS4232 based soundcard driver"); 
-MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); 
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io,"base I/O port for AD1848");
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq,"IRQ for AD1848 chip");
-module_param(dma, int, 0);
-MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip");
-module_param(dma2, int, 0);
-MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip");
-module_param(mpuio, int, 0);
-MODULE_PARM_DESC(mpuio,"MPU 401 base address");
-module_param(mpuirq, int, 0);
-MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ");
-module_param(synthio, int, 0);
-MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port");
-module_param(synthirq, int, 0);
-MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ");
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)");
-module_param(bss, bool, 0);
-MODULE_PARM_DESC(bss,"Enable Bose Sound System Support (default 0)");
-
-/*
- *     Install a CS4232 based card. Need to have ad1848 and mpu401
- *     loaded ready.
- */
-
-/* All cs4232 based cards have the main ad1848 card either as CSC0000 or
- * CSC0100. */
-static const struct pnp_device_id cs4232_pnp_table[] = {
-       { .id = "CSC0100", .driver_data = 0 },
-       { .id = "CSC0000", .driver_data = 0 },
-       /* Guillemot Turtlebeach something appears to be cs4232 compatible
-        * (untested) */
-       { .id = "GIM0100", .driver_data = 0 },
-       { .id = ""}
-};
-
-MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table);
-
-static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
-       struct address_info *isapnpcfg;
-
-       isapnpcfg = kmalloc(sizeof(*isapnpcfg),GFP_KERNEL);
-       if (!isapnpcfg)
-               return -ENOMEM;
-
-       isapnpcfg->irq          = pnp_irq(dev, 0);
-       isapnpcfg->dma          = pnp_dma(dev, 0);
-       isapnpcfg->dma2         = pnp_dma(dev, 1);
-       isapnpcfg->io_base      = pnp_port_start(dev, 0);
-       if (probe_cs4232(isapnpcfg,TRUE) == 0) {
-               printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n");
-               kfree(isapnpcfg);
-               return -ENODEV;
-       }
-       pnp_set_drvdata(dev,isapnpcfg);
-       cs4232_devices++;
-       return 0;
-}
-
-static void __devexit cs4232_pnp_remove(struct pnp_dev *dev)
-{
-       struct address_info *cfg = pnp_get_drvdata(dev);
-       if (cfg) {
-               unload_cs4232(cfg);
-               kfree(cfg);
-       }
-}
-
-static struct pnp_driver cs4232_driver = {
-       .name           = "cs4232",
-       .id_table       = cs4232_pnp_table,
-       .probe          = cs4232_pnp_probe,
-       .remove         = __devexit_p(cs4232_pnp_remove),
-};
-
-static int __init init_cs4232(void)
-{
-#ifdef CONFIG_SOUND_WAVEFRONT_MODULE
-       if(synthio == -1)
-               printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n");
-       else {
-               synth_base = synthio;
-               synth_irq =  synthirq;
-       }
-#else
-       if(synthio != -1)
-               printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n");
-#endif
-       cfg.irq = -1;
-
-       if (isapnp) {
-               pnp_register_driver(&cs4232_driver);
-               if (cs4232_devices)
-                       return 0;
-       }
-
-       if(io==-1||irq==-1||dma==-1)
-       {
-               printk(KERN_ERR "cs4232: Must set io, irq and dma.\n");
-               return -ENODEV;
-       }
-
-       cfg.io_base = io;
-       cfg.irq = irq;
-       cfg.dma = dma;
-       cfg.dma2 = dma2;
-
-       cfg_mpu.io_base = -1;
-       cfg_mpu.irq = -1;
-
-       if (mpuio != -1 && mpuirq != -1) {
-               cfg_mpu.io_base = mpuio;
-               cfg_mpu.irq = mpuirq;
-               probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */
-       }
-
-       if (probe_cs4232(&cfg,FALSE) == 0)
-               return -ENODEV;
-
-       return 0;
-}
-
-static void __exit cleanup_cs4232(void)
-{
-       pnp_unregister_driver(&cs4232_driver);
-        if (cfg.irq != -1)
-               unload_cs4232(&cfg); /* Unloads global MPU as well, if needed */
-}
-
-module_init(init_cs4232);
-module_exit(cleanup_cs4232);
-
-#ifndef MODULE
-static int __init setup_cs4232(char *str)
-{
-       /* io, irq, dma, dma2 mpuio, mpuirq*/
-       int ints[7];
-
-       /* If we have isapnp cards, no need for options */
-       pnp_register_driver(&cs4232_driver);
-       if (cs4232_devices)
-               return 1;
-       
-       str = get_options(str, ARRAY_SIZE(ints), ints);
-       
-       io      = ints[1];
-       irq     = ints[2];
-       dma     = ints[3];
-       dma2    = ints[4];
-       mpuio   = ints[5];
-       mpuirq  = ints[6];
-
-       return 1;
-}
-
-__setup("cs4232=", setup_cs4232);
-#endif
index 71b3134..3eb7827 100644 (file)
@@ -14,7 +14,7 @@ config DMASOUND_ATARI
 
 config DMASOUND_PAULA
        tristate "Amiga DMA sound support"
-       depends on (AMIGA || APUS) && SOUND
+       depends on AMIGA && SOUND
        select DMASOUND
        help
          If you want to use the internal audio of your Amiga in Linux, answer
index 90fc058..202e810 100644 (file)
@@ -91,10 +91,6 @@ static irqreturn_t AmiInterrupt(int irq, void *dummy);
      *  power LED are controlled by the same line.
      */
 
-#ifdef CONFIG_APUS
-#define mach_heartbeat ppc_md.heartbeat
-#endif
-
 static void (*saved_heartbeat)(int) = NULL;
 
 static inline void disable_heartbeat(void)
diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
deleted file mode 100644 (file)
index f5e31f1..0000000
+++ /dev/null
@@ -1,3656 +0,0 @@
-/*
- *     Intel i810 and friends ICH driver for Linux
- *     Alan Cox <alan@redhat.com>
- *
- *  Built from:
- *     Low level code:  Zach Brown (original nonworking i810 OSS driver)
- *                      Jaroslav Kysela <perex@suse.cz> (working ALSA driver)
- *
- *     Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- *     Extended by: Zach Brown <zab@redhat.com>  
- *                     and others..
- *
- *  Hardware Provided By:
- *     Analog Devices (A major AC97 codec maker)
- *     Intel Corp  (you've probably heard of them already)
- *
- *  AC97 clues and assistance provided by
- *     Analog Devices
- *     Zach 'Fufu' Brown
- *     Jeff Garzik
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *     Intel 810 theory of operation
- *
- *     The chipset provides three DMA channels that talk to an AC97
- *     CODEC (AC97 is a digital/analog mixer standard). At its simplest
- *     you get 48Khz audio with basic volume and mixer controls. At the
- *     best you get rate adaption in the codec. We set the card up so
- *     that we never take completion interrupts but instead keep the card
- *     chasing its tail around a ring buffer. This is needed for mmap
- *     mode audio and happens to work rather well for non-mmap modes too.
- *
- *     The board has one output channel for PCM audio (supported) and
- *     a stereo line in and mono microphone input. Again these are normally
- *     locked to 48Khz only. Right now recording is not finished.
- *
- *     There is no midi support, no synth support. Use timidity. To get
- *     esd working you need to use esd -r 48000 as it won't probe 48KHz
- *     by default. mpg123 can't handle 48Khz only audio so use xmms.
- *
- *     Fix The Sound On Dell
- *
- *     Not everyone uses 48KHz. We know of no way to detect this reliably
- *     and certainly not to get the right data. If your i810 audio sounds
- *     stupid you may need to investigate other speeds. According to Analog
- *     they tend to use a 14.318MHz clock which gives you a base rate of
- *     41194Hz.
- *
- *     This is available via the 'ftsodell=1' option. 
- *
- *     If you need to force a specific rate set the clocking= option
- *
- *     This driver is cursed. (Ben LaHaise)
- *
- *  ICH 3 caveats
- *     Intel errata #7 for ICH3 IO. We need to disable SMI stuff
- *     when codec probing. [Not Yet Done]
- *
- *  ICH 4 caveats
- *
- *     The ICH4 has the feature, that the codec ID doesn't have to be 
- *     congruent with the IO connection.
- * 
- *     Therefore, from driver version 0.23 on, there is a "codec ID" <->
- *     "IO register base offset" mapping (card->ac97_id_map) field.
- *   
- *     Juergen "George" Sawinski (jsaw) 
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#define DRIVER_VERSION "1.01"
-
-#define MODULOP2(a, b) ((a) & ((b) - 1))
-#define MASKP2(a, b) ((a) & ~((b) - 1))
-
-static int ftsodell;
-static int strict_clocking;
-static unsigned int clocking;
-static int spdif_locked;
-static int ac97_quirk = AC97_TUNE_DEFAULT;
-
-//#define DEBUG
-//#define DEBUG2
-//#define DEBUG_INTERRUPTS
-//#define DEBUG_MMAP
-//#define DEBUG_MMIO
-
-#define ADC_RUNNING    1
-#define DAC_RUNNING    2
-
-#define I810_FMT_16BIT 1
-#define I810_FMT_STEREO        2
-#define I810_FMT_MASK  3
-
-#define SPDIF_ON       0x0004
-#define SURR_ON                0x0010
-#define CENTER_LFE_ON  0x0020
-#define VOL_MUTED      0x8000
-
-/* the 810's array of pointers to data buffers */
-
-struct sg_item {
-#define BUSADDR_MASK   0xFFFFFFFE
-       u32 busaddr;    
-#define CON_IOC        0x80000000 /* interrupt on completion */
-#define CON_BUFPAD     0x40000000 /* pad underrun with last sample, else 0 */
-#define CON_BUFLEN_MASK        0x0000ffff /* buffer length in samples */
-       u32 control;
-};
-
-/* an instance of the i810 channel */
-#define SG_LEN 32
-struct i810_channel 
-{
-       /* these sg guys should probably be allocated
-          separately as nocache. Must be 8 byte aligned */
-       struct sg_item sg[SG_LEN];      /* 32*8 */
-       u32 offset;                     /* 4 */
-       u32 port;                       /* 4 */
-       u32 used;
-       u32 num;
-};
-
-/*
- * we have 3 separate dma engines.  pcm in, pcm out, and mic.
- * each dma engine has controlling registers.  These goofy
- * names are from the datasheet, but make it easy to write
- * code while leafing through it.
- *
- * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, 
- * mic in 2, s/pdif.   Of special interest is the fact that
- * the upper 3 DMA engines on the ICH4 *must* be accessed
- * via mmio access instead of pio access.
- */
-
-#define ENUM_ENGINE(PRE,DIG)                                                                   \
-enum {                                                                                         \
-       PRE##_BASE =    0x##DIG##0,             /* Base Address */                              \
-       PRE##_BDBAR =   0x##DIG##0,             /* Buffer Descriptor list Base Address */       \
-       PRE##_CIV =     0x##DIG##4,             /* Current Index Value */                       \
-       PRE##_LVI =     0x##DIG##5,             /* Last Valid Index */                          \
-       PRE##_SR =      0x##DIG##6,             /* Status Register */                           \
-       PRE##_PICB =    0x##DIG##8,             /* Position In Current Buffer */                \
-       PRE##_PIV =     0x##DIG##a,             /* Prefetched Index Value */                    \
-       PRE##_CR =      0x##DIG##b              /* Control Register */                          \
-}
-
-ENUM_ENGINE(OFF,0);    /* Offsets */
-ENUM_ENGINE(PI,0);     /* PCM In */
-ENUM_ENGINE(PO,1);     /* PCM Out */
-ENUM_ENGINE(MC,2);     /* Mic In */
-
-enum {
-       GLOB_CNT =      0x2c,                   /* Global Control */
-       GLOB_STA =      0x30,                   /* Global Status */
-       CAS      =      0x34                    /* Codec Write Semaphore Register */
-};
-
-ENUM_ENGINE(MC2,4);     /* Mic In 2 */
-ENUM_ENGINE(PI2,5);     /* PCM In 2 */
-ENUM_ENGINE(SP,6);      /* S/PDIF */
-
-enum {
-       SDM =           0x80                    /* SDATA_IN Map Register */
-};
-
-/* interrupts for a dma engine */
-#define DMA_INT_FIFO           (1<<4)  /* fifo under/over flow */
-#define DMA_INT_COMPLETE       (1<<3)  /* buffer read/write complete and ioc set */
-#define DMA_INT_LVI            (1<<2)  /* last valid done */
-#define DMA_INT_CELV           (1<<1)  /* last valid is current */
-#define DMA_INT_DCH            (1)     /* DMA Controller Halted (happens on LVI interrupts) */
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */
-#define INT_SEC                (1<<11)
-#define INT_PRI                (1<<10)
-#define INT_MC         (1<<7)
-#define INT_PO         (1<<6)
-#define INT_PI         (1<<5)
-#define INT_MO         (1<<2)
-#define INT_NI         (1<<1)
-#define INT_GPI                (1<<0)
-#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
-
-/* magic numbers to protect our data structures */
-#define I810_CARD_MAGIC                0x5072696E /* "Prin" */
-#define I810_STATE_MAGIC       0x63657373 /* "cess" */
-#define I810_DMA_MASK          0xffffffff /* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH               3
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97                 4
-
-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
-/* stream at a minimum for this card to be happy */
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
-/* values are one less than might be expected */
-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
-
-enum {
-       ICH82801AA = 0,
-       ICH82901AB,
-       INTEL440MX,
-       INTELICH2,
-       INTELICH3,
-       INTELICH4,
-       INTELICH5,
-       SI7012,
-       NVIDIA_NFORCE,
-       AMD768,
-       AMD8111
-};
-
-static char * card_names[] = {
-       "Intel ICH 82801AA",
-       "Intel ICH 82901AB",
-       "Intel 440MX",
-       "Intel ICH2",
-       "Intel ICH3",
-       "Intel ICH4",
-       "Intel ICH5",
-       "SiS 7012",
-       "NVIDIA nForce Audio",
-       "AMD 768",
-       "AMD-8111 IOHub"
-};
-
-/* These are capabilities (and bugs) the chipsets _can_ have */
-static struct {
-       int16_t      nr_ac97;
-#define CAP_MMIO                 0x0001
-#define CAP_20BIT_AUDIO_SUPPORT  0x0002
-       u_int16_t flags;
-} card_cap[] = {
-       {  1, 0x0000 }, /* ICH82801AA */
-       {  1, 0x0000 }, /* ICH82901AB */
-       {  1, 0x0000 }, /* INTEL440MX */
-       {  1, 0x0000 }, /* INTELICH2 */
-       {  2, 0x0000 }, /* INTELICH3 */
-       {  3, 0x0003 }, /* INTELICH4 */
-       {  3, 0x0003 }, /* INTELICH5 */
-       /*@FIXME to be verified*/       {  2, 0x0000 }, /* SI7012 */
-       /*@FIXME to be verified*/       {  2, 0x0000 }, /* NVIDIA_NFORCE */
-       /*@FIXME to be verified*/       {  2, 0x0000 }, /* AMD768 */
-       /*@FIXME to be verified*/       {  3, 0x0001 }, /* AMD8111 */
-};
-
-static struct pci_device_id i810_pci_tbl [] = {
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_4,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH5},
-       {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},
-       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7445,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768},
-       {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_5,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
-       {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_18,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
-       {PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_AUDIO,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
-       {0,}
-};
-
-MODULE_DEVICE_TABLE (pci, i810_pci_tbl);
-
-#ifdef CONFIG_PM
-#define PM_SUSPENDED(card) (card->pm_suspended)
-#else
-#define PM_SUSPENDED(card) (0)
-#endif
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct i810_state {
-       unsigned int magic;
-       struct i810_card *card; /* Card info */
-
-       /* single open lock mechanism, only used for recording */
-       struct mutex open_mutex;
-       wait_queue_head_t open_wait;
-
-       /* file mode */
-       mode_t open_mode;
-
-       /* virtual channel number */
-       int virt;
-
-#ifdef CONFIG_PM
-       unsigned int pm_saved_dac_rate,pm_saved_adc_rate;
-#endif
-       struct dmabuf {
-               /* wave sample stuff */
-               unsigned int rate;
-               unsigned char fmt, enable, trigger;
-
-               /* hardware channel */
-               struct i810_channel *read_channel;
-               struct i810_channel *write_channel;
-
-               /* OSS buffer management stuff */
-               void *rawbuf;
-               dma_addr_t dma_handle;
-               unsigned buforder;
-               unsigned numfrag;
-               unsigned fragshift;
-
-               /* our buffer acts like a circular ring */
-               unsigned hwptr;         /* where dma last started, updated by update_ptr */
-               unsigned swptr;         /* where driver last clear/filled, updated by read/write */
-               int count;              /* bytes to be consumed or been generated by dma machine */
-               unsigned total_bytes;   /* total bytes dmaed by hardware */
-
-               unsigned error;         /* number of over/underruns */
-               wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
-               /* redundant, but makes calculations easier */
-               /* what the hardware uses */
-               unsigned dmasize;
-               unsigned fragsize;
-               unsigned fragsamples;
-
-               /* what we tell the user to expect */
-               unsigned userfrags;
-               unsigned userfragsize;
-
-               /* OSS stuff */
-               unsigned mapped:1;
-               unsigned ready:1;
-               unsigned update_flag;
-               unsigned ossfragsize;
-               unsigned ossmaxfrags;
-               unsigned subdivision;
-       } dmabuf;
-};
-
-
-struct i810_card {
-       unsigned int magic;
-
-       /* We keep i810 cards in a linked list */
-       struct i810_card *next;
-
-       /* The i810 has a certain amount of cross channel interaction
-          so we use a single per card lock */
-       spinlock_t lock;
-       
-       /* Control AC97 access serialization */
-       spinlock_t ac97_lock;
-
-       /* PCI device stuff */
-       struct pci_dev * pci_dev;
-       u16 pci_id;
-       u16 pci_id_internal; /* used to access card_cap[] */
-#ifdef CONFIG_PM       
-       u16 pm_suspended;
-       int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
-#endif
-       /* soundcore stuff */
-       int dev_audio;
-
-       /* structures for abstraction of hardware facilities, codecs, banks and channels*/
-       u16    ac97_id_map[NR_AC97];
-       struct ac97_codec *ac97_codec[NR_AC97];
-       struct i810_state *states[NR_HW_CH];
-       struct i810_channel *channel;   /* 1:1 to states[] but diff. lifetime */
-       dma_addr_t chandma;
-
-       u16 ac97_features;
-       u16 ac97_status;
-       u16 channels;
-       
-       /* hardware resources */
-       unsigned long ac97base;
-       unsigned long iobase;
-       u32 irq;
-
-       unsigned long ac97base_mmio_phys;
-       unsigned long iobase_mmio_phys;
-       u_int8_t __iomem *ac97base_mmio;
-       u_int8_t __iomem *iobase_mmio;
-
-       int           use_mmio;
-       
-       /* Function support */
-       struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
-       struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
-       struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
-       void (*free_pcm_channel)(struct i810_card *, int chan);
-
-       /* We have a *very* long init time possibly, so use this to block */
-       /* attempts to open our devices before we are ready (stops oops'es) */
-       int initializing;
-};
-
-/* extract register offset from codec struct */
-#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
-
-#define I810_IOREAD(size, type, card, off)                             \
-({                                                                     \
-       type val;                                                       \
-       if (card->use_mmio)                                             \
-               val=read##size(card->iobase_mmio+off);                  \
-       else                                                            \
-               val=in##size(card->iobase+off);                         \
-       val;                                                            \
-})
-
-#define I810_IOREADL(card, off)                I810_IOREAD(l, u32, card, off)
-#define I810_IOREADW(card, off)                I810_IOREAD(w, u16, card, off)
-#define I810_IOREADB(card, off)                I810_IOREAD(b, u8,  card, off)
-
-#define I810_IOWRITE(size, val, card, off)                             \
-({                                                                     \
-       if (card->use_mmio)                                             \
-               write##size(val, card->iobase_mmio+off);                \
-       else                                                            \
-               out##size(val, card->iobase+off);                       \
-})
-
-#define I810_IOWRITEL(val, card, off)  I810_IOWRITE(l, val, card, off)
-#define I810_IOWRITEW(val, card, off)  I810_IOWRITE(w, val, card, off)
-#define I810_IOWRITEB(val, card, off)  I810_IOWRITE(b, val, card, off)
-
-#define GET_CIV(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_CIV), SG_LEN)
-#define GET_LVI(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_LVI), SG_LEN)
-
-/* set LVI from CIV */
-#define CIV_TO_LVI(card, port, off) \
-       I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI)
-
-static struct ac97_quirk ac97_quirks[] __devinitdata = {
-       {
-               .vendor = 0x0e11,
-               .device = 0x00b8,
-               .name = "Compaq Evo D510C",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x00d8,
-               .name = "Dell Precision 530",   /* AD1885 */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x0126,
-               .name = "Dell Optiplex GX260",  /* AD1981A */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x012d,
-               .name = "Dell Precision 450",   /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {       /* FIXME: which codec? */
-               .vendor = 0x103c,
-               .device = 0x00c3,
-               .name = "Hewlett-Packard onboard",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x12f1,
-               .name = "HP xw8200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x3008,
-               .name = "HP xw4200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x10f1,
-               .device = 0x2665,
-               .name = "Fujitsu-Siemens Celsius",      /* AD1981? */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x10f1,
-               .device = 0x2885,
-               .name = "AMD64 Mobo",   /* ALC650 */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x110a,
-               .device = 0x0056,
-               .name = "Fujitsu-Siemens Scenic",       /* AD1981? */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x11d4,
-               .device = 0x5375,
-               .name = "ADI AD1985 (discrete)",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1462,
-               .device = 0x5470,
-               .name = "MSI P4 ATX 645 Ultra",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1734,
-               .device = 0x0088,
-               .name = "Fujitsu-Siemens D1522",        /* AD1981 */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x8086,
-               .device = 0x4856,
-               .name = "Intel D845WN (82801BA)",
-               .type = AC97_TUNE_SWAP_HP
-       },
-       {
-               .vendor = 0x8086,
-               .device = 0x4d44,
-               .name = "Intel D850EMV2",       /* AD1885 */
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x8086,
-               .device = 0x4d56,
-               .name = "Intel ICH/AD1885",
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x1028,
-               .device = 0x012d,
-               .name = "Dell Precision 450",   /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x3008,
-               .name = "HP xw4200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       {
-               .vendor = 0x103c,
-               .device = 0x12f1,
-               .name = "HP xw8200",    /* AD1981B*/
-               .type = AC97_TUNE_HP_ONLY
-       },
-       { } /* terminator */
-};
-
-static struct i810_card *devs = NULL;
-
-static int i810_open_mixdev(struct inode *inode, struct file *file);
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg);
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
-{
-       if(card->channel[1].used==1)
-               return NULL;
-       card->channel[1].used=1;
-       return &card->channel[1];
-}
-
-static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card)
-{
-       if(card->channel[0].used==1)
-               return NULL;
-       card->channel[0].used=1;
-       return &card->channel[0];
-}
-
-static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card)
-{
-       if(card->channel[2].used==1)
-               return NULL;
-       card->channel[2].used=1;
-       return &card->channel[2];
-}
-
-static void i810_free_pcm_channel(struct i810_card *card, int channel)
-{
-       card->channel[channel].used=0;
-}
-
-static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate )
-{
-       unsigned long id = 0L;
-
-       id = (i810_ac97_get(codec, AC97_VENDOR_ID1) << 16);
-       id |= i810_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
-#ifdef DEBUG
-       printk ( "i810_audio: codec = %s, codec_id = 0x%08lx\n", codec->name, id);
-#endif
-       switch ( id ) {
-               case 0x41445361: /* AD1886 */
-                       if (rate == 48000) {
-                               return 1;
-                       }
-                       break;
-               default: /* all other codecs, until we know otherwiae */
-                       if (rate == 48000 || rate == 44100 || rate == 32000) {
-                               return 1;
-                       }
-                       break;
-       }
-       return (0);
-}
-
-/* i810_set_spdif_output
- * 
- *  Configure the S/PDIF output transmitter. When we turn on
- *  S/PDIF, we turn off the analog output. This may not be
- *  the right thing to do.
- *
- *  Assumptions:
- *     The DSP sample rate must already be set to a supported
- *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
- */
-static int i810_set_spdif_output(struct i810_state *state, int slots, int rate)
-{
-       int     vol;
-       int     aud_reg;
-       int     r = 0;
-       struct ac97_codec *codec = state->card->ac97_codec[0];
-
-       if(!codec->codec_ops->digital) {
-               state->card->ac97_status &= ~SPDIF_ON;
-       } else {
-               if ( slots == -1 ) { /* Turn off S/PDIF */
-                       codec->codec_ops->digital(codec, 0, 0, 0);
-                       /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
-                       if ( !(state->card->ac97_status & VOL_MUTED) ) {
-                               aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-                               i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
-                       }
-                       state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
-                       return 0;
-               }
-
-               vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-               state->card->ac97_status = vol & VOL_MUTED;
-               
-               r = codec->codec_ops->digital(codec, slots, rate, 0);
-
-               if(r)
-                       state->card->ac97_status |= SPDIF_ON;
-               else
-                       state->card->ac97_status &= ~SPDIF_ON;
-
-               /* Mute the analog output */
-               /* Should this only mute the PCM volume??? */
-               i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));
-       }
-       return r;
-}
-
-/* i810_set_dac_channels
- *
- *  Configure the codec's multi-channel DACs
- *
- *  The logic is backwards. Setting the bit to 1 turns off the DAC. 
- *
- *  What about the ICH? We currently configure it using the
- *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC, 
- *  does that imply that we want the ICH set to support
- *  these channels?
- *  
- *  TODO:
- *    vailidate that the codec really supports these DACs
- *    before turning them on. 
- */
-static void i810_set_dac_channels(struct i810_state *state, int channel)
-{
-       int     aud_reg;
-       struct ac97_codec *codec = state->card->ac97_codec[0];
-       
-       /* No codec, no setup */
-       
-       if(codec == NULL)
-               return;
-
-       aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
-       aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
-       state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
-
-       switch ( channel ) {
-               case 2: /* always enabled */
-                       break;
-               case 4:
-                       aud_reg &= ~AC97_EA_PRJ;
-                       state->card->ac97_status |= SURR_ON;
-                       break;
-               case 6:
-                       aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
-                       state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
-                       break;
-               default:
-                       break;
-       }
-       i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-
-/* set playback sample rate */
-static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
-{      
-       struct dmabuf *dmabuf = &state->dmabuf;
-       u32 new_rate;
-       struct ac97_codec *codec=state->card->ac97_codec[0];
-       
-       if(!(state->card->ac97_features&0x0001))
-       {
-               dmabuf->rate = clocking;
-#ifdef DEBUG
-               printk("Asked for %d Hz, but ac97_features says we only do %dHz.  Sorry!\n",
-                      rate,clocking);
-#endif                
-               return clocking;
-       }
-                       
-       if (rate > 48000)
-               rate = 48000;
-       if (rate < 8000)
-               rate = 8000;
-       dmabuf->rate = rate;
-               
-       /*
-        *      Adjust for misclocked crap
-        */
-       rate = ( rate * clocking)/48000;
-       if(strict_clocking && rate < 8000) {
-               rate = 8000;
-               dmabuf->rate = (rate * 48000)/clocking;
-       }
-
-        new_rate=ac97_set_dac_rate(codec, rate);
-       if(new_rate != rate) {
-               dmabuf->rate = (new_rate * 48000)/clocking;
-       }
-#ifdef DEBUG
-       printk("i810_audio: called i810_set_dac_rate : asked for %d, got %d\n", rate, dmabuf->rate);
-#endif
-       rate = new_rate;
-       return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       u32 new_rate;
-       struct ac97_codec *codec=state->card->ac97_codec[0];
-       
-       if(!(state->card->ac97_features&0x0001))
-       {
-               dmabuf->rate = clocking;
-               return clocking;
-       }
-                       
-       if (rate > 48000)
-               rate = 48000;
-       if (rate < 8000)
-               rate = 8000;
-       dmabuf->rate = rate;
-
-       /*
-        *      Adjust for misclocked crap
-        */
-        
-       rate = ( rate * clocking)/48000;
-       if(strict_clocking && rate < 8000) {
-               rate = 8000;
-               dmabuf->rate = (rate * 48000)/clocking;
-       }
-
-       new_rate = ac97_set_adc_rate(codec, rate);
-       
-       if(new_rate != rate) {
-               dmabuf->rate = (new_rate * 48000)/clocking;
-               rate = new_rate;
-       }
-#ifdef DEBUG
-       printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate);
-#endif
-       return dmabuf->rate;
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
-   called with spinlock held! */
-   
-static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned int civ, offset, port, port_picb, bytes = 2;
-       
-       if (!dmabuf->enable)
-               return 0;
-
-       if (rec)
-               port = dmabuf->read_channel->port;
-       else
-               port = dmabuf->write_channel->port;
-
-       if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {
-               port_picb = port + OFF_SR;
-               bytes = 1;
-       } else
-               port_picb = port + OFF_PICB;
-
-       do {
-               civ = GET_CIV(state->card, port);
-               offset = I810_IOREADW(state->card, port_picb);
-               /* Must have a delay here! */ 
-               if(offset == 0)
-                       udelay(1);
-               /* Reread both registers and make sure that that total
-                * offset from the first reading to the second is 0.
-                * There is an issue with SiS hardware where it will count
-                * picb down to 0, then update civ to the next value,
-                * then set the new picb to fragsize bytes.  We can catch
-                * it between the civ update and the picb update, making
-                * it look as though we are 1 fragsize ahead of where we
-                * are.  The next to we get the address though, it will
-                * be back in the right place, and we will suddenly think
-                * we just went forward dmasize - fragsize bytes, causing
-                * totally stupid *huge* dma overrun messages.  We are
-                * assuming that the 1us delay is more than long enough
-                * that we won't have to worry about the chip still being
-                * out of sync with reality ;-)
-                */
-       } while (civ != GET_CIV(state->card, port) || offset != I810_IOREADW(state->card, port_picb));
-                
-       return (((civ + 1) * dmabuf->fragsize - (bytes * offset))
-               % dmabuf->dmasize);
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct i810_card *card = state->card;
-
-       dmabuf->enable &= ~ADC_RUNNING;
-       I810_IOWRITEB(0, card, PI_CR);
-       // wait for the card to acknowledge shutdown
-       while( I810_IOREADB(card, PI_CR) != 0 ) ;
-       // now clear any latent interrupt bits (like the halt bit)
-       if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-               I810_IOWRITEB( I810_IOREADB(card, PI_PICB), card, PI_PICB );
-       else
-               I810_IOWRITEB( I810_IOREADB(card, PI_SR), card, PI_SR );
-       I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PI, card, GLOB_STA);
-}
-
-static void stop_adc(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __stop_adc(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_adc(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-
-       if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
-           (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-               dmabuf->enable |= ADC_RUNNING;
-               // Interrupt enable, LVI enable, DMA enable
-               I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PI_CR);
-       }
-}
-
-static void start_adc(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __start_adc(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct i810_card *card = state->card;
-
-       dmabuf->enable &= ~DAC_RUNNING;
-       I810_IOWRITEB(0, card, PO_CR);
-       // wait for the card to acknowledge shutdown
-       while( I810_IOREADB(card, PO_CR) != 0 ) ;
-       // now clear any latent interrupt bits (like the halt bit)
-       if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-               I810_IOWRITEB( I810_IOREADB(card, PO_PICB), card, PO_PICB );
-       else
-               I810_IOWRITEB( I810_IOREADB(card, PO_SR), card, PO_SR );
-       I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PO, card, GLOB_STA);
-}
-
-static void stop_dac(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __stop_dac(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}      
-
-static inline void __start_dac(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-
-       if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
-           (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-               dmabuf->enable |= DAC_RUNNING;
-               // Interrupt enable, LVI enable, DMA enable
-               I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PO_CR);
-       }
-}
-static void start_dac(struct i810_state *state)
-{
-       struct i810_card *card = state->card;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       __start_dac(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback and recording buffer should be allocated separately */
-static int alloc_dmabuf(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       void *rawbuf= NULL;
-       int order, size;
-       struct page *page, *pend;
-
-       /* If we don't have any oss frag params, then use our default ones */
-       if(dmabuf->ossmaxfrags == 0)
-               dmabuf->ossmaxfrags = 4;
-       if(dmabuf->ossfragsize == 0)
-               dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;
-       size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-
-       if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
-               return 0;
-       /* alloc enough to satisfy the oss params */
-       for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
-               if ( (PAGE_SIZE<<order) > size )
-                       continue;
-               if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
-                                                  PAGE_SIZE << order,
-                                                  &dmabuf->dma_handle)))
-                       break;
-       }
-       if (!rawbuf)
-               return -ENOMEM;
-
-
-#ifdef DEBUG
-       printk("i810_audio: allocated %ld (order = %d) bytes at %p\n",
-              PAGE_SIZE << order, order, rawbuf);
-#endif
-
-       dmabuf->ready  = dmabuf->mapped = 0;
-       dmabuf->rawbuf = rawbuf;
-       dmabuf->buforder = order;
-       
-       /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-       pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
-       for (page = virt_to_page(rawbuf); page <= pend; page++)
-               SetPageReserved(page);
-
-       return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct page *page, *pend;
-
-       if (dmabuf->rawbuf) {
-               /* undo marking the pages as reserved */
-               pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
-               for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
-                       ClearPageReserved(page);
-               pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,
-                                   dmabuf->rawbuf, dmabuf->dma_handle);
-       }
-       dmabuf->rawbuf = NULL;
-       dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct i810_state *state, unsigned rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       struct i810_channel *c;
-       struct sg_item *sg;
-       unsigned long flags;
-       int ret;
-       unsigned fragint;
-       int i;
-
-       spin_lock_irqsave(&state->card->lock, flags);
-       if(dmabuf->enable & DAC_RUNNING)
-               __stop_dac(state);
-       if(dmabuf->enable & ADC_RUNNING)
-               __stop_adc(state);
-       dmabuf->total_bytes = 0;
-       dmabuf->count = dmabuf->error = 0;
-       dmabuf->swptr = dmabuf->hwptr = 0;
-       spin_unlock_irqrestore(&state->card->lock, flags);
-
-       /* allocate DMA buffer, let alloc_dmabuf determine if we are already
-        * allocated well enough or if we should replace the current buffer
-        * (assuming one is already allocated, if it isn't, then allocate it).
-        */
-       if ((ret = alloc_dmabuf(state)))
-               return ret;
-
-       /* FIXME: figure out all this OSS fragment stuff */
-       /* I did, it now does what it should according to the OSS API.  DL */
-       /* We may not have realloced our dmabuf, but the fragment size to
-        * fragment number ratio may have changed, so go ahead and reprogram
-        * things
-        */
-       dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
-       dmabuf->numfrag = SG_LEN;
-       dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag;
-       dmabuf->fragsamples = dmabuf->fragsize >> 1;
-       dmabuf->fragshift = ffs(dmabuf->fragsize) - 1;
-       dmabuf->userfragsize = dmabuf->ossfragsize;
-       dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize;
-
-       memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
-       if(dmabuf->ossmaxfrags == 4) {
-               fragint = 8;
-       } else if (dmabuf->ossmaxfrags == 8) {
-               fragint = 4;
-       } else if (dmabuf->ossmaxfrags == 16) {
-               fragint = 2;
-       } else {
-               fragint = 1;
-       }
-       /*
-        *      Now set up the ring 
-        */
-       if(dmabuf->read_channel)
-               c = dmabuf->read_channel;
-       else
-               c = dmabuf->write_channel;
-       while(c != NULL) {
-               sg=&c->sg[0];
-               /*
-                *      Load up 32 sg entries and take an interrupt at half
-                *      way (we might want more interrupts later..) 
-                */
-         
-               for(i=0;i<dmabuf->numfrag;i++)
-               {
-                       sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
-                       // the card will always be doing 16bit stereo
-                       sg->control=dmabuf->fragsamples;
-                       if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
-                               sg->control <<= 1;
-                       sg->control|=CON_BUFPAD;
-                       // set us up to get IOC interrupts as often as needed to
-                       // satisfy numfrag requirements, no more
-                       if( ((i+1) % fragint) == 0) {
-                               sg->control|=CON_IOC;
-                       }
-                       sg++;
-               }
-               spin_lock_irqsave(&state->card->lock, flags);
-               I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* reset DMA machine */
-               while( I810_IOREADB(state->card, c->port+OFF_CR) & 0x02 ) ;
-               I810_IOWRITEL((u32)state->card->chandma +
-                   c->num*sizeof(struct i810_channel),
-                   state->card, c->port+OFF_BDBAR);
-               CIV_TO_LVI(state->card, c->port, 0);
-
-               spin_unlock_irqrestore(&state->card->lock, flags);
-
-               if(c != dmabuf->write_channel)
-                       c = dmabuf->write_channel;
-               else
-                       c = NULL;
-       }
-       
-       /* set the ready flag for the dma buffer */
-       dmabuf->ready = 1;
-
-#ifdef DEBUG
-       printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d,\n\tnumfrag = %d, "
-              "fragsize = %d dmasize = %d\n",
-              dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
-              dmabuf->fragsize, dmabuf->dmasize);
-#endif
-
-       return 0;
-}
-
-static void __i810_update_lvi(struct i810_state *state, int rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int x, port;
-       int trigger;
-       int count, fragsize;
-       void (*start)(struct i810_state *);
-
-       count = dmabuf->count;
-       if (rec) {
-               port = dmabuf->read_channel->port;
-               trigger = PCM_ENABLE_INPUT;
-               start = __start_adc;
-               count = dmabuf->dmasize - count;
-       } else {
-               port = dmabuf->write_channel->port;
-               trigger = PCM_ENABLE_OUTPUT;
-               start = __start_dac;
-       }
-
-       /* Do not process partial fragments. */
-       fragsize = dmabuf->fragsize;
-       if (count < fragsize)
-               return;
-
-       /* if we are currently stopped, then our CIV is actually set to our
-        * *last* sg segment and we are ready to wrap to the next.  However,
-        * if we set our LVI to the last sg segment, then it won't wrap to
-        * the next sg segment, it won't even get a start.  So, instead, when
-        * we are stopped, we set both the LVI value and also we increment
-        * the CIV value to the next sg segment to be played so that when
-        * we call start, things will operate properly.  Since the CIV can't
-        * be written to directly for this purpose, we set the LVI to CIV + 1
-        * temporarily.  Once the engine has started we set the LVI to its
-        * final value.
-        */
-       if (!dmabuf->enable && dmabuf->ready) {
-               if (!(dmabuf->trigger & trigger))
-                       return;
-
-               CIV_TO_LVI(state->card, port, 1);
-
-               start(state);
-               while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | (1<<2))))
-                       ;
-       }
-
-       /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */
-       x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize);
-       x >>= dmabuf->fragshift;
-       I810_IOWRITEB(x, state->card, port + OFF_LVI);
-}
-
-static void i810_update_lvi(struct i810_state *state, int rec)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-
-       if(!dmabuf->ready)
-               return;
-       spin_lock_irqsave(&state->card->lock, flags);
-       __i810_update_lvi(state, rec);
-       spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void i810_update_ptr(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned hwptr;
-       unsigned fragmask, dmamask;
-       int diff;
-
-       fragmask = MASKP2(~0, dmabuf->fragsize);
-       dmamask = MODULOP2(~0, dmabuf->dmasize);
-
-       /* error handling and process wake up for ADC */
-       if (dmabuf->enable == ADC_RUNNING) {
-               /* update hardware pointer */
-               hwptr = i810_get_dma_addr(state, 1) & fragmask;
-               diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
-               printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
-               dmabuf->hwptr = hwptr;
-               dmabuf->total_bytes += diff;
-               dmabuf->count += diff;
-               if (dmabuf->count > dmabuf->dmasize) {
-                       /* buffer underrun or buffer overrun */
-                       /* this is normal for the end of a read */
-                       /* only give an error if we went past the */
-                       /* last valid sg entry */
-                       if (GET_CIV(state->card, PI_BASE) !=
-                           GET_LVI(state->card, PI_BASE)) {
-                               printk(KERN_WARNING "i810_audio: DMA overrun on read\n");
-                               dmabuf->error++;
-                       }
-               }
-               if (diff)
-                       wake_up(&dmabuf->wait);
-       }
-       /* error handling and process wake up for DAC */
-       if (dmabuf->enable == DAC_RUNNING) {
-               /* update hardware pointer */
-               hwptr = i810_get_dma_addr(state, 0) & fragmask;
-               diff = (hwptr - dmabuf->hwptr) & dmamask;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
-               printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
-               dmabuf->hwptr = hwptr;
-               dmabuf->total_bytes += diff;
-               dmabuf->count -= diff;
-               if (dmabuf->count < 0) {
-                       /* buffer underrun or buffer overrun */
-                       /* this is normal for the end of a write */
-                       /* only give an error if we went past the */
-                       /* last valid sg entry */
-                       if (GET_CIV(state->card, PO_BASE) !=
-                           GET_LVI(state->card, PO_BASE)) {
-                               printk(KERN_WARNING "i810_audio: DMA overrun on write\n");
-                               printk("i810_audio: CIV %d, LVI %d, hwptr %x, "
-                                       "count %d\n",
-                                       GET_CIV(state->card, PO_BASE),
-                                       GET_LVI(state->card, PO_BASE),
-                                       dmabuf->hwptr, dmabuf->count);
-                               dmabuf->error++;
-                       }
-               }
-               if (diff)
-                       wake_up(&dmabuf->wait);
-       }
-}
-
-static inline int i810_get_free_write_space(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int free;
-
-       i810_update_ptr(state);
-       // catch underruns during playback
-       if (dmabuf->count < 0) {
-               dmabuf->count = 0;
-               dmabuf->swptr = dmabuf->hwptr;
-       }
-       free = dmabuf->dmasize - dmabuf->count;
-       if(free < 0)
-               return(0);
-       return(free);
-}
-
-static inline int i810_get_available_read_data(struct i810_state *state)
-{
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int avail;
-
-       i810_update_ptr(state);
-       // catch overruns during record
-       if (dmabuf->count > dmabuf->dmasize) {
-               dmabuf->count = dmabuf->dmasize;
-               dmabuf->swptr = dmabuf->hwptr;
-       }
-       avail = dmabuf->count;
-       if(avail < 0)
-               return(0);
-       return(avail);
-}
-
-static inline void fill_partial_frag(struct dmabuf *dmabuf)
-{
-       unsigned fragsize;
-       unsigned swptr, len;
-
-       fragsize = dmabuf->fragsize;
-       swptr = dmabuf->swptr;
-       len = fragsize - MODULOP2(dmabuf->swptr, fragsize);
-       if (len == fragsize)
-               return;
-
-       memset(dmabuf->rawbuf + swptr, '\0', len);
-       dmabuf->swptr = MODULOP2(swptr + len, dmabuf->dmasize);
-       dmabuf->count += len;
-}
-
-static int drain_dac(struct i810_state *state, int signals_allowed)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-       unsigned long tmo;
-       int count;
-
-       if (!dmabuf->ready)
-               return 0;
-       if(dmabuf->mapped) {
-               stop_dac(state);
-               return 0;
-       }
-
-       spin_lock_irqsave(&state->card->lock, flags);
-
-       fill_partial_frag(dmabuf);
-
-       /* 
-        * This will make sure that our LVI is correct, that our
-        * pointer is updated, and that the DAC is running.  We
-        * have to force the setting of dmabuf->trigger to avoid
-        * any possible deadlocks.
-        */
-       dmabuf->trigger = PCM_ENABLE_OUTPUT;
-       __i810_update_lvi(state, 0);
-
-       spin_unlock_irqrestore(&state->card->lock, flags);
-
-       add_wait_queue(&dmabuf->wait, &wait);
-       for (;;) {
-
-               spin_lock_irqsave(&state->card->lock, flags);
-               i810_update_ptr(state);
-               count = dmabuf->count;
-
-               /* It seems that we have to set the current state to
-                * TASK_INTERRUPTIBLE every time to make the process
-                * really go to sleep.  This also has to be *after* the
-                * update_ptr() call because update_ptr is likely to
-                * do a wake_up() which will unset this before we ever
-                * try to sleep, resuling in a tight loop in this code
-                * instead of actually sleeping and waiting for an
-                * interrupt to wake us up!
-                */
-               __set_current_state(signals_allowed ?
-                                   TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
-               spin_unlock_irqrestore(&state->card->lock, flags);
-
-               if (count <= 0)
-                       break;
-
-                if (signal_pending(current) && signals_allowed) {
-                        break;
-                }
-
-               /*
-                * set the timeout to significantly longer than it *should*
-                * take for the DAC to drain the DMA buffer
-                */
-               tmo = (count * HZ) / (dmabuf->rate);
-               if (!schedule_timeout(tmo >= 2 ? tmo : 2)){
-                       printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n");
-                       count = 0;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&dmabuf->wait, &wait);
-       if(count > 0 && signal_pending(current) && signals_allowed)
-               return -ERESTARTSYS;
-       stop_dac(state);
-       return 0;
-}
-
-static void i810_channel_interrupt(struct i810_card *card)
-{
-       int i, count;
-       
-#ifdef DEBUG_INTERRUPTS
-       printk("CHANNEL ");
-#endif
-       for(i=0;i<NR_HW_CH;i++)
-       {
-               struct i810_state *state = card->states[i];
-               struct i810_channel *c;
-               struct dmabuf *dmabuf;
-               unsigned long port;
-               u16 status;
-               
-               if(!state)
-                       continue;
-               if(!state->dmabuf.ready)
-                       continue;
-               dmabuf = &state->dmabuf;
-               if(dmabuf->enable & DAC_RUNNING) {
-                       c=dmabuf->write_channel;
-               } else if(dmabuf->enable & ADC_RUNNING) {
-                       c=dmabuf->read_channel;
-               } else  /* This can occur going from R/W to close */
-                       continue;
-               
-               port = c->port;
-
-               if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-                       status = I810_IOREADW(card, port + OFF_PICB);
-               else
-                       status = I810_IOREADW(card, port + OFF_SR);
-
-#ifdef DEBUG_INTERRUPTS
-               printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status);
-#endif
-               if(status & DMA_INT_COMPLETE)
-               {
-                       /* only wake_up() waiters if this interrupt signals
-                        * us being beyond a userfragsize of data open or
-                        * available, and i810_update_ptr() does that for
-                        * us
-                        */
-                       i810_update_ptr(state);
-#ifdef DEBUG_INTERRUPTS
-                       printk("COMP %d ", dmabuf->hwptr /
-                                       dmabuf->fragsize);
-#endif
-               }
-               if(status & (DMA_INT_LVI | DMA_INT_DCH))
-               {
-                       /* wake_up() unconditionally on LVI and DCH */
-                       i810_update_ptr(state);
-                       wake_up(&dmabuf->wait);
-#ifdef DEBUG_INTERRUPTS
-                       if(status & DMA_INT_LVI)
-                               printk("LVI ");
-                       if(status & DMA_INT_DCH)
-                               printk("DCH -");
-#endif
-                       count = dmabuf->count;
-                       if(dmabuf->enable & ADC_RUNNING)
-                               count = dmabuf->dmasize - count;
-                       if (count >= (int)dmabuf->fragsize) {
-                               I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 1, card, port+OFF_CR);
-#ifdef DEBUG_INTERRUPTS
-                               printk(" CONTINUE ");
-#endif
-                       } else {
-                               if (dmabuf->enable & DAC_RUNNING)
-                                       __stop_dac(state);
-                               if (dmabuf->enable & ADC_RUNNING)
-                                       __stop_adc(state);
-                               dmabuf->enable = 0;
-#ifdef DEBUG_INTERRUPTS
-                               printk(" STOP ");
-#endif
-                       }
-               }
-               if(card->pci_id == PCI_DEVICE_ID_SI_7012)
-                       I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_PICB);
-               else
-                       I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_SR);
-       }
-#ifdef DEBUG_INTERRUPTS
-       printk(")\n");
-#endif
-}
-
-static irqreturn_t i810_interrupt(int irq, void *dev_id)
-{
-       struct i810_card *card = dev_id;
-       u32 status;
-
-       spin_lock(&card->lock);
-
-       status = I810_IOREADL(card, GLOB_STA);
-
-       if(!(status & INT_MASK)) 
-       {
-               spin_unlock(&card->lock);
-               return IRQ_NONE;  /* not for us */
-       }
-
-       if(status & (INT_PO|INT_PI|INT_MC))
-               i810_channel_interrupt(card);
-
-       /* clear 'em */
-       I810_IOWRITEL(status & INT_MASK, card, GLOB_STA);
-       spin_unlock(&card->lock);
-       return IRQ_HANDLED;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is
-   waiting to be copied to the user's buffer.  It is filled by the dma
-   machine and drained by this loop. */
-
-static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_card *card=state ? state->card : NULL;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       ssize_t ret;
-       unsigned long flags;
-       unsigned int swptr;
-       int cnt;
-       int pending;
-        DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
-       printk("i810_audio: i810_read called, count = %d\n", count);
-#endif
-
-       if (dmabuf->mapped)
-               return -ENXIO;
-       if (dmabuf->enable & DAC_RUNNING)
-               return -ENODEV;
-       if (!dmabuf->read_channel) {
-               dmabuf->ready = 0;
-               dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
-               if (!dmabuf->read_channel) {
-                       return -EBUSY;
-               }
-       }
-       if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-               return ret;
-       if (!access_ok(VERIFY_WRITE, buffer, count))
-               return -EFAULT;
-       ret = 0;
-
-       pending = 0;
-
-        add_wait_queue(&dmabuf->wait, &waita);
-       while (count > 0) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               spin_lock_irqsave(&card->lock, flags);
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        schedule();
-                        if (signal_pending(current)) {
-                                if (!ret) ret = -EAGAIN;
-                                break;
-                        }
-                        continue;
-                }
-               cnt = i810_get_available_read_data(state);
-               swptr = dmabuf->swptr;
-               // this is to make the copy_to_user simpler below
-               if(cnt > (dmabuf->dmasize - swptr))
-                       cnt = dmabuf->dmasize - swptr;
-               spin_unlock_irqrestore(&card->lock, flags);
-
-               if (cnt > count)
-                       cnt = count;
-               if (cnt <= 0) {
-                       unsigned long tmo;
-                       /*
-                        * Don't let us deadlock.  The ADC won't start if
-                        * dmabuf->trigger isn't set.  A call to SETTRIGGER
-                        * could have turned it off after we set it to on
-                        * previously.
-                        */
-                       dmabuf->trigger = PCM_ENABLE_INPUT;
-                       /*
-                        * This does three things.  Updates LVI to be correct,
-                        * makes sure the ADC is running, and updates the
-                        * hwptr.
-                        */
-                       i810_update_lvi(state,1);
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret) ret = -EAGAIN;
-                               goto done;
-                       }
-                       /* Set the timeout to how long it would take to fill
-                        * two of our buffers.  If we haven't been woke up
-                        * by then, then we know something is wrong.
-                        */
-                       tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
-                       /* There are two situations when sleep_on_timeout returns, one is when
-                          the interrupt is serviced correctly and the process is waked up by
-                          ISR ON TIME. Another is when timeout is expired, which means that
-                          either interrupt is NOT serviced correctly (pending interrupt) or it
-                          is TOO LATE for the process to be scheduled to run (scheduler latency)
-                          which results in a (potential) buffer overrun. And worse, there is
-                          NOTHING we can do to prevent it. */
-                       if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
-                               printk(KERN_ERR "i810_audio: recording schedule timeout, "
-                                      "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-                                      dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-                                      dmabuf->hwptr, dmabuf->swptr);
-#endif
-                               /* a buffer overrun, we delay the recovery until next time the
-                                  while loop begin and we REALLY have space to record */
-                       }
-                       if (signal_pending(current)) {
-                               ret = ret ? ret : -ERESTARTSYS;
-                               goto done;
-                       }
-                       continue;
-               }
-
-               if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
-                       if (!ret) ret = -EFAULT;
-                       goto done;
-               }
-
-               swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
-               spin_lock_irqsave(&card->lock, flags);
-
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        continue;
-                }
-               dmabuf->swptr = swptr;
-               pending = dmabuf->count -= cnt;
-               spin_unlock_irqrestore(&card->lock, flags);
-
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-       }
- done:
-       pending = dmabuf->dmasize - pending;
-       if (dmabuf->enable || pending >= dmabuf->userfragsize)
-               i810_update_lvi(state, 1);
-        set_current_state(TASK_RUNNING);
-        remove_wait_queue(&dmabuf->wait, &waita);
-
-       return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
-   the soundcard.  it is drained by the dma machine and filled by this loop. */
-static ssize_t i810_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_card *card=state ? state->card : NULL;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       ssize_t ret;
-       unsigned long flags;
-       unsigned int swptr = 0;
-       int pending;
-       int cnt;
-        DECLARE_WAITQUEUE(waita, current);
-
-#ifdef DEBUG2
-       printk("i810_audio: i810_write called, count = %d\n", count);
-#endif
-
-       if (dmabuf->mapped)
-               return -ENXIO;
-       if (dmabuf->enable & ADC_RUNNING)
-               return -ENODEV;
-       if (!dmabuf->write_channel) {
-               dmabuf->ready = 0;
-               dmabuf->write_channel = card->alloc_pcm_channel(card);
-               if(!dmabuf->write_channel)
-                       return -EBUSY;
-       }
-       if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-               return ret;
-       if (!access_ok(VERIFY_READ, buffer, count))
-               return -EFAULT;
-       ret = 0;
-
-       pending = 0;
-
-        add_wait_queue(&dmabuf->wait, &waita);
-       while (count > 0) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               spin_lock_irqsave(&state->card->lock, flags);
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        schedule();
-                        if (signal_pending(current)) {
-                                if (!ret) ret = -EAGAIN;
-                                break;
-                        }
-                        continue;
-                }
-
-               cnt = i810_get_free_write_space(state);
-               swptr = dmabuf->swptr;
-               /* Bound the maximum size to how much we can copy to the
-                * dma buffer before we hit the end.  If we have more to
-                * copy then it will get done in a second pass of this
-                * loop starting from the beginning of the buffer.
-                */
-               if(cnt > (dmabuf->dmasize - swptr))
-                       cnt = dmabuf->dmasize - swptr;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-
-#ifdef DEBUG2
-               printk(KERN_INFO "i810_audio: i810_write: %d bytes available space\n", cnt);
-#endif
-               if (cnt > count)
-                       cnt = count;
-               if (cnt <= 0) {
-                       unsigned long tmo;
-                       // There is data waiting to be played
-                       /*
-                        * Force the trigger setting since we would
-                        * deadlock with it set any other way
-                        */
-                       dmabuf->trigger = PCM_ENABLE_OUTPUT;
-                       i810_update_lvi(state,0);
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret) ret = -EAGAIN;
-                               goto ret;
-                       }
-                       /* Not strictly correct but works */
-                       tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
-                       /* There are two situations when sleep_on_timeout returns, one is when
-                          the interrupt is serviced correctly and the process is waked up by
-                          ISR ON TIME. Another is when timeout is expired, which means that
-                          either interrupt is NOT serviced correctly (pending interrupt) or it
-                          is TOO LATE for the process to be scheduled to run (scheduler latency)
-                          which results in a (potential) buffer underrun. And worse, there is
-                          NOTHING we can do to prevent it. */
-                       if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-#ifdef DEBUG
-                               printk(KERN_ERR "i810_audio: playback schedule timeout, "
-                                      "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-                                      dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-                                      dmabuf->hwptr, dmabuf->swptr);
-#endif
-                               /* a buffer underrun, we delay the recovery until next time the
-                                  while loop begin and we REALLY have data to play */
-                               //return ret;
-                       }
-                       if (signal_pending(current)) {
-                               if (!ret) ret = -ERESTARTSYS;
-                               goto ret;
-                       }
-                       continue;
-               }
-               if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) {
-                       if (!ret) ret = -EFAULT;
-                       goto ret;
-               }
-
-               swptr = MODULOP2(swptr + cnt, dmabuf->dmasize);
-
-               spin_lock_irqsave(&state->card->lock, flags);
-                if (PM_SUSPENDED(card)) {
-                        spin_unlock_irqrestore(&card->lock, flags);
-                        continue;
-                }
-
-               dmabuf->swptr = swptr;
-               pending = dmabuf->count += cnt;
-
-               count -= cnt;
-               buffer += cnt;
-               ret += cnt;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-       }
-ret:
-       if (dmabuf->enable || pending >= dmabuf->userfragsize)
-               i810_update_lvi(state, 0);
-        set_current_state(TASK_RUNNING);
-        remove_wait_queue(&dmabuf->wait, &waita);
-
-       return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-       unsigned int mask = 0;
-
-       if(!dmabuf->ready)
-               return 0;
-       poll_wait(file, &dmabuf->wait, wait);
-       spin_lock_irqsave(&state->card->lock, flags);
-       if (dmabuf->enable & ADC_RUNNING ||
-           dmabuf->trigger & PCM_ENABLE_INPUT) {
-               if (i810_get_available_read_data(state) >= 
-                   (signed)dmabuf->userfragsize)
-                       mask |= POLLIN | POLLRDNORM;
-       }
-       if (dmabuf->enable & DAC_RUNNING ||
-           dmabuf->trigger & PCM_ENABLE_OUTPUT) {
-               if (i810_get_free_write_space(state) >=
-                   (signed)dmabuf->userfragsize)
-                       mask |= POLLOUT | POLLWRNORM;
-       }
-       spin_unlock_irqrestore(&state->card->lock, flags);
-       return mask;
-}
-
-static int i810_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       int ret = -EINVAL;
-       unsigned long size;
-
-       lock_kernel();
-       if (vma->vm_flags & VM_WRITE) {
-               if (!dmabuf->write_channel &&
-                   (dmabuf->write_channel =
-                    state->card->alloc_pcm_channel(state->card)) == NULL) {
-                       ret = -EBUSY;
-                       goto out;
-               }
-       }
-       if (vma->vm_flags & VM_READ) {
-               if (!dmabuf->read_channel &&
-                   (dmabuf->read_channel = 
-                    state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
-                       ret = -EBUSY;
-                       goto out;
-               }
-       }
-       if ((ret = prog_dmabuf(state, 0)) != 0)
-               goto out;
-
-       ret = -EINVAL;
-       if (vma->vm_pgoff != 0)
-               goto out;
-       size = vma->vm_end - vma->vm_start;
-       if (size > (PAGE_SIZE << dmabuf->buforder))
-               goto out;
-       ret = -EAGAIN;
-       if (remap_pfn_range(vma, vma->vm_start,
-                            virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
-                            size, vma->vm_page_prot))
-               goto out;
-       dmabuf->mapped = 1;
-       dmabuf->trigger = 0;
-       ret = 0;
-#ifdef DEBUG_MMAP
-       printk("i810_audio: mmap'ed %ld bytes of data space\n", size);
-#endif
-out:
-       unlock_kernel();
-       return ret;
-}
-
-static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_channel *c = NULL;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-       audio_buf_info abinfo;
-       count_info cinfo;
-       unsigned int i_glob_cnt;
-       int val = 0, ret;
-       struct ac97_codec *codec = state->card->ac97_codec[0];
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-
-#ifdef DEBUG
-       printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *p : 0);
-#endif
-
-       switch (cmd) 
-       {
-       case OSS_GETVERSION:
-#ifdef DEBUG
-               printk("OSS_GETVERSION\n");
-#endif
-               return put_user(SOUND_VERSION, p);
-
-       case SNDCTL_DSP_RESET:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_RESET\n");
-#endif
-               spin_lock_irqsave(&state->card->lock, flags);
-               if (dmabuf->enable == DAC_RUNNING) {
-                       c = dmabuf->write_channel;
-                       __stop_dac(state);
-               }
-               if (dmabuf->enable == ADC_RUNNING) {
-                       c = dmabuf->read_channel;
-                       __stop_adc(state);
-               }
-               if (c != NULL) {
-                       I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* reset DMA machine */
-                       while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 )
-                               cpu_relax();
-                       I810_IOWRITEL((u32)state->card->chandma +
-                           c->num*sizeof(struct i810_channel),
-                           state->card, c->port+OFF_BDBAR);
-                       CIV_TO_LVI(state->card, c->port, 0);
-               }
-
-               spin_unlock_irqrestore(&state->card->lock, flags);
-               synchronize_irq(state->card->pci_dev->irq);
-               dmabuf->ready = 0;
-               dmabuf->swptr = dmabuf->hwptr = 0;
-               dmabuf->count = dmabuf->total_bytes = 0;
-               return 0;
-
-       case SNDCTL_DSP_SYNC:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SYNC\n");
-#endif
-               if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
-                       return 0;
-               if((val = drain_dac(state, 1)))
-                       return val;
-               dmabuf->total_bytes = 0;
-               return 0;
-
-       case SNDCTL_DSP_SPEED: /* set smaple rate */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SPEED\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (val >= 0) {
-                       if (file->f_mode & FMODE_WRITE) {
-                               if ( (state->card->ac97_status & SPDIF_ON) ) {  /* S/PDIF Enabled */
-                                       /* AD1886 only supports 48000, need to check that */
-                                       if ( i810_valid_spdif_rate ( codec, val ) ) {
-                                               /* Set DAC rate */
-                                               i810_set_spdif_output ( state, -1, 0 );
-                                               stop_dac(state);
-                                               dmabuf->ready = 0;
-                                               spin_lock_irqsave(&state->card->lock, flags);
-                                               i810_set_dac_rate(state, val);
-                                               spin_unlock_irqrestore(&state->card->lock, flags);
-                                               /* Set S/PDIF transmitter rate. */
-                                               i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val );
-                                               if ( ! (state->card->ac97_status & SPDIF_ON) ) {
-                                                       val = dmabuf->rate;
-                                               }
-                                       } else { /* Not a valid rate for S/PDIF, ignore it */
-                                               val = dmabuf->rate;
-                                       }
-                               } else {
-                                       stop_dac(state);
-                                       dmabuf->ready = 0;
-                                       spin_lock_irqsave(&state->card->lock, flags);
-                                       i810_set_dac_rate(state, val);
-                                       spin_unlock_irqrestore(&state->card->lock, flags);
-                               }
-                       }
-                       if (file->f_mode & FMODE_READ) {
-                               stop_adc(state);
-                               dmabuf->ready = 0;
-                               spin_lock_irqsave(&state->card->lock, flags);
-                               i810_set_adc_rate(state, val);
-                               spin_unlock_irqrestore(&state->card->lock, flags);
-                       }
-               }
-               return put_user(dmabuf->rate, p);
-
-       case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_STEREO\n");
-#endif
-               if (dmabuf->enable & DAC_RUNNING) {
-                       stop_dac(state);
-               }
-               if (dmabuf->enable & ADC_RUNNING) {
-                       stop_adc(state);
-               }
-               return put_user(1, p);
-
-       case SNDCTL_DSP_GETBLKSIZE:
-               if (file->f_mode & FMODE_WRITE) {
-                       if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
-                               return val;
-               }
-               if (file->f_mode & FMODE_READ) {
-                       if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
-                               return val;
-               }
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
-#endif
-               return put_user(dmabuf->userfragsize, p);
-
-       case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETFMTS\n");
-#endif
-               return put_user(AFMT_S16_LE, p);
-
-       case SNDCTL_DSP_SETFMT: /* Select sample format */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETFMT\n");
-#endif
-               return put_user(AFMT_S16_LE, p);
-
-       case SNDCTL_DSP_CHANNELS:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_CHANNELS\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               if (val > 0) {
-                       if (dmabuf->enable & DAC_RUNNING) {
-                               stop_dac(state);
-                       }
-                       if (dmabuf->enable & ADC_RUNNING) {
-                               stop_adc(state);
-                       }
-               } else {
-                       return put_user(state->card->channels, p);
-               }
-
-               /* ICH and ICH0 only support 2 channels */
-               if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5
-                    || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5) 
-                       return put_user(2, p);
-       
-               /* Multi-channel support was added with ICH2. Bits in */
-               /* Global Status and Global Control register are now  */
-               /* used to indicate this.                             */
-
-                i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT);
-
-               /* Current # of channels enabled */
-               if ( i_glob_cnt & 0x0100000 )
-                       ret = 4;
-               else if ( i_glob_cnt & 0x0200000 )
-                       ret = 6;
-               else
-                       ret = 2;
-
-               switch ( val ) {
-                       case 2: /* 2 channels is always supported */
-                               I810_IOWRITEL(i_glob_cnt & 0xffcfffff,
-                                    state->card, GLOB_CNT);
-                               /* Do we need to change mixer settings????  */
-                               break;
-                       case 4: /* Supported on some chipsets, better check first */
-                               if ( state->card->channels >= 4 ) {
-                                       I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000,
-                                             state->card, GLOB_CNT);
-                                       /* Do we need to change mixer settings??? */
-                               } else {
-                                       val = ret;
-                               }
-                               break;
-                       case 6: /* Supported on some chipsets, better check first */
-                               if ( state->card->channels >= 6 ) {
-                                       I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000,
-                                             state->card, GLOB_CNT);
-                                       /* Do we need to change mixer settings??? */
-                               } else {
-                                       val = ret;
-                               }
-                               break;
-                       default: /* nothing else is ever supported by the chipset */
-                               val = ret;
-                               break;
-               }
-
-               return put_user(val, p);
-
-       case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
-               /* we update the swptr to the end of the last sg segment then return */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_POST\n");
-#endif
-               if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
-                       return 0;
-               if((dmabuf->swptr % dmabuf->fragsize) != 0) {
-                       val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
-                       dmabuf->swptr += val;
-                       dmabuf->count += val;
-               }
-               return 0;
-
-       case SNDCTL_DSP_SUBDIVIDE:
-               if (dmabuf->subdivision)
-                       return -EINVAL;
-               if (get_user(val, p))
-                       return -EFAULT;
-               if (val != 1 && val != 2 && val != 4)
-                       return -EINVAL;
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
-#endif
-               dmabuf->subdivision = val;
-               dmabuf->ready = 0;
-               return 0;
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               dmabuf->ossfragsize = 1<<(val & 0xffff);
-               dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-               if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
-                       return -EINVAL;
-               /*
-                * Bound the frag size into our allowed range of 256 - 4096
-                */
-               if (dmabuf->ossfragsize < 256)
-                       dmabuf->ossfragsize = 256;
-               else if (dmabuf->ossfragsize > 4096)
-                       dmabuf->ossfragsize = 4096;
-               /*
-                * The numfrags could be something reasonable, or it could
-                * be 0xffff meaning "Give me as much as possible".  So,
-                * we check the numfrags * fragsize doesn't exceed our
-                * 64k buffer limit, nor is it less than our 8k minimum.
-                * If it fails either one of these checks, then adjust the
-                * number of fragments, not the size of them.  It's OK if
-                * our number of fragments doesn't equal 32 or anything
-                * like our hardware based number now since we are using
-                * a different frag count for the hardware.  Before we get
-                * into this though, bound the maxfrags to avoid overflow
-                * issues.  A reasonable bound would be 64k / 256 since our
-                * maximum buffer size is 64k and our minimum frag size is
-                * 256.  On the other end, our minimum buffer size is 8k and
-                * our maximum frag size is 4k, so the lower bound should
-                * be 2.
-                */
-
-               if(dmabuf->ossmaxfrags > 256)
-                       dmabuf->ossmaxfrags = 256;
-               else if (dmabuf->ossmaxfrags < 2)
-                       dmabuf->ossmaxfrags = 2;
-
-               val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-               while (val < 8192) {
-                   val <<= 1;
-                   dmabuf->ossmaxfrags <<= 1;
-               }
-               while (val > 65536) {
-                   val >>= 1;
-                   dmabuf->ossmaxfrags >>= 1;
-               }
-               dmabuf->ready = 0;
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
-                       dmabuf->ossfragsize, dmabuf->ossmaxfrags);
-#endif
-
-               return 0;
-
-       case SNDCTL_DSP_GETOSPACE:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               i810_update_ptr(state);
-               abinfo.fragsize = dmabuf->userfragsize;
-               abinfo.fragstotal = dmabuf->userfrags;
-               if (dmabuf->mapped)
-                       abinfo.bytes = dmabuf->dmasize;
-               else
-                       abinfo.bytes = i810_get_free_write_space(state);
-               abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
-                       abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
-               return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETOPTR:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               val = i810_get_free_write_space(state);
-               cinfo.bytes = dmabuf->total_bytes;
-               cinfo.ptr = dmabuf->hwptr;
-               cinfo.blocks = val/dmabuf->userfragsize;
-               if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-                       dmabuf->count += val;
-                       dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-                       __i810_update_lvi(state, 0);
-               }
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
-                       cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
-               return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETISPACE:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               abinfo.bytes = i810_get_available_read_data(state);
-               abinfo.fragsize = dmabuf->userfragsize;
-               abinfo.fragstotal = dmabuf->userfrags;
-               abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
-                       abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
-#endif
-               return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_GETIPTR:
-               if (!(file->f_mode & FMODE_READ))
-                       return -EINVAL;
-               if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-                       return val;
-               spin_lock_irqsave(&state->card->lock, flags);
-               val = i810_get_available_read_data(state);
-               cinfo.bytes = dmabuf->total_bytes;
-               cinfo.blocks = val/dmabuf->userfragsize;
-               cinfo.ptr = dmabuf->hwptr;
-               if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-                       dmabuf->count -= val;
-                       dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-                       __i810_update_lvi(state, 1);
-               }
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
-                       cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
-               return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-       case SNDCTL_DSP_NONBLOCK:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_NONBLOCK\n");
-#endif
-               file->f_flags |= O_NONBLOCK;
-               return 0;
-
-       case SNDCTL_DSP_GETCAPS:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETCAPS\n");
-#endif
-           return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
-                           p);
-
-       case SNDCTL_DSP_GETTRIGGER:
-               val = 0;
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
-#endif
-               return put_user(dmabuf->trigger, p);
-
-       case SNDCTL_DSP_SETTRIGGER:
-               if (get_user(val, p))
-                       return -EFAULT;
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-               printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
-#endif
-               /* silently ignore invalid PCM_ENABLE_xxx bits,
-                * like the other drivers do
-                */
-               if (!(file->f_mode & FMODE_READ ))
-                       val &= ~PCM_ENABLE_INPUT;
-               if (!(file->f_mode & FMODE_WRITE ))
-                       val &= ~PCM_ENABLE_OUTPUT;
-               if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
-                       stop_adc(state);
-               }
-               if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
-                       stop_dac(state);
-               }
-               dmabuf->trigger = val;
-               if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
-                       if (!dmabuf->write_channel) {
-                               dmabuf->ready = 0;
-                               dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
-                               if (!dmabuf->write_channel)
-                                       return -EBUSY;
-                       }
-                       if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-                               return ret;
-                       if (dmabuf->mapped) {
-                               spin_lock_irqsave(&state->card->lock, flags);
-                               i810_update_ptr(state);
-                               dmabuf->count = 0;
-                               dmabuf->swptr = dmabuf->hwptr;
-                               dmabuf->count = i810_get_free_write_space(state);
-                               dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
-                               spin_unlock_irqrestore(&state->card->lock, flags);
-                       }
-                       i810_update_lvi(state, 0);
-                       start_dac(state);
-               }
-               if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
-                       if (!dmabuf->read_channel) {
-                               dmabuf->ready = 0;
-                               dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
-                               if (!dmabuf->read_channel)
-                                       return -EBUSY;
-                       }
-                       if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-                               return ret;
-                       if (dmabuf->mapped) {
-                               spin_lock_irqsave(&state->card->lock, flags);
-                               i810_update_ptr(state);
-                               dmabuf->swptr = dmabuf->hwptr;
-                               dmabuf->count = 0;
-                               spin_unlock_irqrestore(&state->card->lock, flags);
-                       }
-                       i810_update_lvi(state, 1);
-                       start_adc(state);
-               }
-               return 0;
-
-       case SNDCTL_DSP_SETDUPLEX:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETDUPLEX\n");
-#endif
-               return -EINVAL;
-
-       case SNDCTL_DSP_GETODELAY:
-               if (!(file->f_mode & FMODE_WRITE))
-                       return -EINVAL;
-               spin_lock_irqsave(&state->card->lock, flags);
-               i810_update_ptr(state);
-               val = dmabuf->count;
-               spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
-#endif
-               return put_user(val, p);
-
-       case SOUND_PCM_READ_RATE:
-#ifdef DEBUG
-               printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
-#endif
-               return put_user(dmabuf->rate, p);
-
-       case SOUND_PCM_READ_CHANNELS:
-#ifdef DEBUG
-               printk("SOUND_PCM_READ_CHANNELS\n");
-#endif
-               return put_user(2, p);
-
-       case SOUND_PCM_READ_BITS:
-#ifdef DEBUG
-               printk("SOUND_PCM_READ_BITS\n");
-#endif
-               return put_user(AFMT_S16_LE, p);
-
-       case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_SETSPDIF\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               /* Check to make sure the codec supports S/PDIF transmitter */
-
-               if((state->card->ac97_features & 4)) {
-                       /* mask out the transmitter speed bits so the user can't set them */
-                       val &= ~0x3000;
-
-                       /* Add the current transmitter speed bits to the passed value */
-                       ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
-                       val |= (ret & 0x3000);
-
-                       i810_ac97_set(codec, AC97_SPDIF_CONTROL, val);
-                       if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) {
-                               printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
-                               return -EFAULT;
-                       }
-               }
-#ifdef DEBUG
-               else 
-                       printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
-               return put_user(val, p);
-
-       case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETSPDIF\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-
-               /* Check to make sure the codec supports S/PDIF transmitter */
-
-               if(!(state->card->ac97_features & 4)) {
-#ifdef DEBUG
-                       printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
-#endif
-                       val = 0;
-               } else {
-                       val = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
-               }
-               //return put_user((val & 0xcfff), p);
-               return put_user(val, p);
-                       
-       case SNDCTL_DSP_GETCHANNELMASK:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_GETCHANNELMASK\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-               
-               /* Based on AC'97 DAC support, not ICH hardware */
-               val = DSP_BIND_FRONT;
-               if ( state->card->ac97_features & 0x0004 )
-                       val |= DSP_BIND_SPDIF;
-
-               if ( state->card->ac97_features & 0x0080 )
-                       val |= DSP_BIND_SURR;
-               if ( state->card->ac97_features & 0x0140 )
-                       val |= DSP_BIND_CENTER_LFE;
-
-               return put_user(val, p);
-
-       case SNDCTL_DSP_BIND_CHANNEL:
-#ifdef DEBUG
-               printk("SNDCTL_DSP_BIND_CHANNEL\n");
-#endif
-               if (get_user(val, p))
-                       return -EFAULT;
-               if ( val == DSP_BIND_QUERY ) {
-                       val = DSP_BIND_FRONT; /* Always report this as being enabled */
-                       if ( state->card->ac97_status & SPDIF_ON ) 
-                               val |= DSP_BIND_SPDIF;
-                       else {
-                               if ( state->card->ac97_status & SURR_ON )
-                                       val |= DSP_BIND_SURR;
-                               if ( state->card->ac97_status & CENTER_LFE_ON )
-                                       val |= DSP_BIND_CENTER_LFE;
-                       }
-               } else {  /* Not a query, set it */
-                       if (!(file->f_mode & FMODE_WRITE))
-                               return -EINVAL;
-                       if ( dmabuf->enable == DAC_RUNNING ) {
-                               stop_dac(state);
-                       }
-                       if ( val & DSP_BIND_SPDIF ) {  /* Turn on SPDIF */
-                               /*  Ok, this should probably define what slots
-                                *  to use. For now, we'll only set it to the
-                                *  defaults:
-                                * 
-                                *   non multichannel codec maps to slots 3&4
-                                *   2 channel codec maps to slots 7&8
-                                *   4 channel codec maps to slots 6&9
-                                *   6 channel codec maps to slots 10&11
-                                *
-                                *  there should be some way for the app to
-                                *  select the slot assignment.
-                                */
-       
-                               i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, dmabuf->rate );
-                               if ( !(state->card->ac97_status & SPDIF_ON) )
-                                       val &= ~DSP_BIND_SPDIF;
-                       } else {
-                               int mask;
-                               int channels;
-
-                               /* Turn off S/PDIF if it was on */
-                               if ( state->card->ac97_status & SPDIF_ON ) 
-                                       i810_set_spdif_output ( state, -1, 0 );
-                               
-                               mask = val & (DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE);
-                               switch (mask) {
-                                       case DSP_BIND_FRONT:
-                                               channels = 2;
-                                               break;
-                                       case DSP_BIND_FRONT|DSP_BIND_SURR:
-                                               channels = 4;
-                                               break;
-                                       case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
-                                               channels = 6;
-                                               break;
-                                       default:
-                                               val = DSP_BIND_FRONT;
-                                               channels = 2;
-                                               break;
-                               }
-                               i810_set_dac_channels ( state, channels );
-
-                               /* check that they really got turned on */
-                               if (!(state->card->ac97_status & SURR_ON))
-                                       val &= ~DSP_BIND_SURR;
-                               if (!(state->card->ac97_status & CENTER_LFE_ON))
-                                       val &= ~DSP_BIND_CENTER_LFE;
-                       }
-               }
-               return put_user(val, p);
-               
-       case SNDCTL_DSP_MAPINBUF:
-       case SNDCTL_DSP_MAPOUTBUF:
-       case SNDCTL_DSP_SETSYNCRO:
-       case SOUND_PCM_WRITE_FILTER:
-       case SOUND_PCM_READ_FILTER:
-#ifdef DEBUG
-               printk("SNDCTL_* -EINVAL\n");
-#endif
-               return -EINVAL;
-       }
-       return -EINVAL;
-}
-
-static int i810_open(struct inode *inode, struct file *file)
-{
-       int i = 0;
-       struct i810_card *card = devs;
-       struct i810_state *state = NULL;
-       struct dmabuf *dmabuf = NULL;
-
-       /* find an avaiable virtual channel (instance of /dev/dsp) */
-       while (card != NULL) {
-               /*
-                * If we are initializing and then fail, card could go
-                * away unuexpectedly while we are in the for() loop.
-                * So, check for card on each iteration before we check
-                * for card->initializing to avoid a possible oops.
-                * This usually only matters for times when the driver is
-                * autoloaded by kmod.
-                */
-               for (i = 0; i < 50 && card && card->initializing; i++) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ/20);
-               }
-               for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
-                       if (card->states[i] == NULL) {
-                               state = card->states[i] = (struct i810_state *)
-                                       kzalloc(sizeof(struct i810_state), GFP_KERNEL);
-                               if (state == NULL)
-                                       return -ENOMEM;
-                               dmabuf = &state->dmabuf;
-                               goto found_virt;
-                       }
-               }
-               card = card->next;
-       }
-       /* no more virtual channel avaiable */
-       if (!state)
-               return -ENODEV;
-
-found_virt:
-       /* initialize the virtual channel */
-       state->virt = i;
-       state->card = card;
-       state->magic = I810_STATE_MAGIC;
-       init_waitqueue_head(&dmabuf->wait);
-       mutex_init(&state->open_mutex);
-       file->private_data = state;
-       dmabuf->trigger = 0;
-
-       /* allocate hardware channels */
-       if(file->f_mode & FMODE_READ) {
-               if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
-                       kfree (card->states[i]);
-                       card->states[i] = NULL;
-                       return -EBUSY;
-               }
-               dmabuf->trigger |= PCM_ENABLE_INPUT;
-               i810_set_adc_rate(state, 8000);
-       }
-       if(file->f_mode & FMODE_WRITE) {
-               if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
-                       /* make sure we free the record channel allocated above */
-                       if(file->f_mode & FMODE_READ)
-                               card->free_pcm_channel(card,dmabuf->read_channel->num);
-                       kfree (card->states[i]);
-                       card->states[i] = NULL;
-                       return -EBUSY;
-               }
-               /* Initialize to 8kHz?  What if we don't support 8kHz? */
-               /*  Let's change this to check for S/PDIF stuff */
-       
-               dmabuf->trigger |= PCM_ENABLE_OUTPUT;
-               if ( spdif_locked ) {
-                       i810_set_dac_rate(state, spdif_locked);
-                       i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
-               } else {
-                       i810_set_dac_rate(state, 8000);
-                       /* Put the ACLink in 2 channel mode by default */
-                       i = I810_IOREADL(card, GLOB_CNT);
-                       I810_IOWRITEL(i & 0xffcfffff, card, GLOB_CNT);
-               }
-       }
-               
-       /* set default sample format. According to OSS Programmer's Guide  /dev/dsp
-          should be default to unsigned 8-bits, mono, with sample rate 8kHz and
-          /dev/dspW will accept 16-bits sample, but we don't support those so we
-          set it immediately to stereo and 16bit, which is all we do support */
-       dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO;
-       dmabuf->ossfragsize = 0;
-       dmabuf->ossmaxfrags  = 0;
-       dmabuf->subdivision  = 0;
-
-       state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
-       return nonseekable_open(inode, file);
-}
-
-static int i810_release(struct inode *inode, struct file *file)
-{
-       struct i810_state *state = (struct i810_state *)file->private_data;
-       struct i810_card *card = state->card;
-       struct dmabuf *dmabuf = &state->dmabuf;
-       unsigned long flags;
-
-       lock_kernel();
-
-       /* stop DMA state machine and free DMA buffers/channels */
-       if(dmabuf->trigger & PCM_ENABLE_OUTPUT) {
-               drain_dac(state, 0);
-       }
-       if(dmabuf->trigger & PCM_ENABLE_INPUT) {
-               stop_adc(state);
-       }
-       spin_lock_irqsave(&card->lock, flags);
-       dealloc_dmabuf(state);
-       if (file->f_mode & FMODE_WRITE) {
-               state->card->free_pcm_channel(state->card, dmabuf->write_channel->num);
-       }
-       if (file->f_mode & FMODE_READ) {
-               state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
-       }
-
-       state->card->states[state->virt] = NULL;
-       kfree(state);
-       spin_unlock_irqrestore(&card->lock, flags);
-       unlock_kernel();
-
-       return 0;
-}
-
-static /*const*/ struct file_operations i810_audio_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .read           = i810_read,
-       .write          = i810_write,
-       .poll           = i810_poll,
-       .ioctl          = i810_ioctl,
-       .mmap           = i810_mmap,
-       .open           = i810_open,
-       .release        = i810_release,
-};
-
-/* Write AC97 codec registers */
-
-static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
-               udelay(1);
-       
-#ifdef DEBUG_MMIO
-       {
-               u16 ans = readw(card->ac97base_mmio + reg_set);
-               printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
-               return ans;
-       }
-#else
-       return readw(card->ac97base_mmio + reg_set);
-#endif
-}
-
-static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (I810_IOREADB(card, CAS) & 1)) 
-               udelay(1);
-       
-       return inw(card->ac97base + reg_set);
-}
-
-static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
-               udelay(1);
-       
-       writew(data, card->ac97base_mmio + reg_set);
-
-#ifdef DEBUG_MMIO
-       printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
-#endif
-}
-
-static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
-{
-       struct i810_card *card = dev->private_data;
-       int count = 100;
-       u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
-       
-       while(count-- && (I810_IOREADB(card, CAS) & 1)) 
-               udelay(1);
-       
-        outw(data, card->ac97base + reg_set);
-}
-
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
-{
-       struct i810_card *card = dev->private_data;
-       u16 ret;
-       
-       spin_lock(&card->ac97_lock);
-       if (card->use_mmio) {
-               ret = i810_ac97_get_mmio(dev, reg);
-       }
-       else {
-               ret = i810_ac97_get_io(dev, reg);
-       }
-       spin_unlock(&card->ac97_lock);
-       
-       return ret;
-}
-
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
-{
-       struct i810_card *card = dev->private_data;
-       
-       spin_lock(&card->ac97_lock);
-       if (card->use_mmio) {
-               i810_ac97_set_mmio(dev, reg, data);
-       }
-       else {
-               i810_ac97_set_io(dev, reg, data);
-       }
-       spin_unlock(&card->ac97_lock);
-}
-
-
-/* OSS /dev/mixer file operation methods */
-
-static int i810_open_mixdev(struct inode *inode, struct file *file)
-{
-       int i;
-       int minor = iminor(inode);
-       struct i810_card *card = devs;
-
-       for (card = devs; card != NULL; card = card->next) {
-               /*
-                * If we are initializing and then fail, card could go
-                * away unuexpectedly while we are in the for() loop.
-                * So, check for card on each iteration before we check
-                * for card->initializing to avoid a possible oops.
-                * This usually only matters for times when the driver is
-                * autoloaded by kmod.
-                */
-               for (i = 0; i < 50 && card && card->initializing; i++) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ/20);
-               }
-               for (i = 0; i < NR_AC97 && card && !card->initializing; i++) 
-                       if (card->ac97_codec[i] != NULL &&
-                           card->ac97_codec[i]->dev_mixer == minor) {
-                               file->private_data = card->ac97_codec[i];
-                               return nonseekable_open(inode, file);
-                       }
-       }
-       return -ENODEV;
-}
-
-static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
-       return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const*/ struct file_operations i810_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .ioctl          = i810_ioctl_mixdev,
-       .open           = i810_open_mixdev,
-};
-
-/* AC97 codec initialisation.  These small functions exist so we don't
-   duplicate code between module init and apm resume */
-
-static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
-{
-       u32 reg = I810_IOREADL(card, GLOB_STA);
-       switch (ac97_number) {
-       case 0:
-               return reg & (1<<8);
-       case 1: 
-               return reg & (1<<9);
-       case 2:
-               return reg & (1<<28);
-       }
-       return 0;
-}
-
-static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
-{
-       i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
-       i810_ac97_set(codec,AC97_EXTENDED_STATUS,
-                     i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800);
-       
-       return (i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1);
-}
-
-
-static int i810_ac97_probe_and_powerup(struct i810_card *card,struct ac97_codec *codec)
-{
-       /* Returns 0 on failure */
-       int i;
-
-       if (ac97_probe_codec(codec) == 0) return 0;
-       
-       /* power it all up */
-       i810_ac97_set(codec, AC97_POWER_CONTROL,
-                     i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
-
-       /* wait for analog ready */
-       for (i=100; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
-       {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ/20);
-       } 
-       return i;
-}
-
-static int is_new_ich(u16 pci_id)
-{
-       switch (pci_id) {
-       case PCI_DEVICE_ID_INTEL_82801DB_5:
-       case PCI_DEVICE_ID_INTEL_82801EB_5:
-       case PCI_DEVICE_ID_INTEL_ESB_5:
-       case PCI_DEVICE_ID_INTEL_ICH6_18:
-               return 1;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static inline int ich_use_mmio(struct i810_card *card)
-{
-       return is_new_ich(card->pci_id) && card->use_mmio;
-}
-
-/**
- *     i810_ac97_power_up_bus  -       bring up AC97 link
- *     @card : ICH audio device to power up
- *
- *     Bring up the ACLink AC97 codec bus
- */
-static int i810_ac97_power_up_bus(struct i810_card *card)
-{      
-       u32 reg = I810_IOREADL(card, GLOB_CNT);
-       int i;
-       int primary_codec_id = 0;
-
-       if((reg&2)==0)  /* Cold required */
-               reg|=2;
-       else
-               reg|=4; /* Warm */
-               
-       reg&=~8;        /* ACLink on */
-       
-       /* At this point we deassert AC_RESET # */
-       I810_IOWRITEL(reg , card, GLOB_CNT);
-
-       /* We must now allow time for the Codec initialisation.
-          600mS is the specified time */
-               
-       for(i=0;i<10;i++)
-       {
-               if((I810_IOREADL(card, GLOB_CNT)&4)==0)
-                       break;
-
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ/20);
-       }
-       if(i==10)
-       {
-               printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");
-               return 0;
-       }
-
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ/2);
-
-       /*
-        *      See if the primary codec comes ready. This must happen
-        *      before we start doing DMA stuff
-        */     
-       /* see i810_ac97_init for the next 10 lines (jsaw) */
-       if (card->use_mmio)
-               readw(card->ac97base_mmio);
-       else
-               inw(card->ac97base);
-       if (ich_use_mmio(card)) {
-               primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
-               printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
-                      primary_codec_id);
-       }
-
-       if(! i810_ac97_exists(card, primary_codec_id))
-       {
-               printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(HZ);   /* actually 600mS by the spec */
-
-               if(i810_ac97_exists(card, primary_codec_id))
-                       printk("OK\n");
-               else 
-                       printk("no response.\n");
-       }
-       if (card->use_mmio)
-               readw(card->ac97base_mmio);
-       else
-               inw(card->ac97base);
-       return 1;
-}
-
-static int __devinit i810_ac97_init(struct i810_card *card)
-{
-       int num_ac97 = 0;
-       int ac97_id;
-       int total_channels = 0;
-       int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
-       struct ac97_codec *codec;
-       u16 eid;
-       u32 reg;
-
-       if(!i810_ac97_power_up_bus(card)) return 0;
-
-       /* Number of channels supported */
-       /* What about the codec?  Just because the ICH supports */
-       /* multiple channels doesn't mean the codec does.       */
-       /* we'll have to modify this in the codec section below */
-       /* to reflect what the codec has.                       */
-       /* ICH and ICH0 only support 2 channels so don't bother */
-       /* to check....                                         */
-
-       card->channels = 2;
-       reg = I810_IOREADL(card, GLOB_STA);
-       if ( reg & 0x0200000 )
-               card->channels = 6;
-       else if ( reg & 0x0100000 )
-               card->channels = 4;
-       printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
-       printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
-       reg = I810_IOREADL(card, GLOB_CNT);
-       I810_IOWRITEL(reg & 0xffcfffff, card, GLOB_CNT);
-               
-       for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) 
-               card->ac97_codec[num_ac97] = NULL;
-
-       /*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
-       if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
-
-       for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
-               /* codec reset */
-               printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
-               if (card->use_mmio)
-                       readw(card->ac97base_mmio + 0x80*num_ac97);
-               else
-                       inw(card->ac97base + 0x80*num_ac97);
-
-               /* If we have the SDATA_IN Map Register, as on ICH4, we
-                  do not loop thru all possible codec IDs but thru all 
-                  possible IO channels. Bit 0:1 of SDM then holds the 
-                  last codec ID spoken to. 
-               */
-               if (ich_use_mmio(card)) {
-                       ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
-                       printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
-                              num_ac97, ac97_id);
-               }
-               else {
-                       ac97_id = num_ac97;
-               }
-
-               /* The ICH programmer's reference says you should   */
-               /* check the ready status before probing. So we chk */
-               /*   What do we do if it's not ready?  Wait and try */
-               /*   again, or abort?                               */
-               if (!i810_ac97_exists(card, ac97_id)) {
-                       if(num_ac97 == 0)
-                               printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
-               }
-               
-               if ((codec = ac97_alloc_codec()) == NULL)
-                       return -ENOMEM;
-
-               /* initialize some basic codec information, other fields will be filled
-                  in ac97_probe_codec */
-               codec->private_data = card;
-               codec->id = ac97_id;
-               card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
-
-               if (card->use_mmio) {   
-                       codec->codec_read = i810_ac97_get_mmio;
-                       codec->codec_write = i810_ac97_set_mmio;
-               }
-               else {
-                       codec->codec_read = i810_ac97_get_io;
-                       codec->codec_write = i810_ac97_set_io;
-               }
-       
-               if(!i810_ac97_probe_and_powerup(card,codec)) {
-                       printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
-                       ac97_release_codec(codec);
-                       break;  /* it didn't work */
-               }
-               /* Store state information about S/PDIF transmitter */
-               card->ac97_status = 0;
-               
-               /* Don't attempt to get eid until powerup is complete */
-               eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-
-               if(eid==0xFFFF)
-               {
-                       printk(KERN_WARNING "i810_audio: no codec attached ?\n");
-                       ac97_release_codec(codec);
-                       break;
-               }
-               
-               /* Check for an AC97 1.0 soft modem (ID1) */
-               
-               if(codec->modem)
-               {
-                       printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id);
-                       ac97_release_codec(codec);
-                       continue;
-               }
-               
-               card->ac97_features = eid;
-
-               /* Now check the codec for useful features to make up for
-                  the dumbness of the 810 hardware engine */
-
-               if(!(eid&0x0001))
-                       printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");
-               else
-               {
-                       if(!i810_ac97_enable_variable_rate(codec)) {
-                               printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n");
-                               card->ac97_features&=~1;
-                       }                       
-               }
-               
-               /* Turn on the amplifier */
-
-               codec->codec_write(codec, AC97_POWER_CONTROL, 
-                        codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
-                               
-               /* Determine how many channels the codec(s) support   */
-               /*   - The primary codec always supports 2            */
-               /*   - If the codec supports AMAP, surround DACs will */
-               /*     automaticlly get assigned to slots.            */
-               /*     * Check for surround DACs and increment if     */
-               /*       found.                                       */
-               /*   - Else check if the codec is revision 2.2        */
-               /*     * If surround DACs exist, assign them to slots */
-               /*       and increment channel count.                 */
-
-               /* All of this only applies to ICH2 and above. ICH    */
-               /* and ICH0 only support 2 channels.  ICH2 will only  */
-               /* support multiple codecs in a "split audio" config. */
-               /* as described above.                                */
-
-               /* TODO: Remove all the debugging messages!           */
-
-               if((eid & 0xc000) == 0) /* primary codec */
-                       total_channels += 2; 
-
-               if(eid & 0x200) { /* GOOD, AMAP support */
-                       if (eid & 0x0080) /* L/R Surround channels */
-                               total_channels += 2;
-                       if (eid & 0x0140) /* LFE and Center channels */
-                               total_channels += 2;
-                       printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
-               } else if (eid & 0x0400) {  /* this only works on 2.2 compliant codecs */
-                       eid &= 0xffcf;
-                       if((eid & 0xc000) != 0) {
-                               switch ( total_channels ) {
-                                       case 2:
-                                               /* Set dsa1, dsa0 to 01 */
-                                               eid |= 0x0010;
-                                               break;
-                                       case 4:
-                                               /* Set dsa1, dsa0 to 10 */
-                                               eid |= 0x0020;
-                                               break;
-                                       case 6:
-                                               /* Set dsa1, dsa0 to 11 */
-                                               eid |= 0x0030;
-                                               break;
-                               }
-                               total_channels += 2;
-                       }
-                       i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
-                       eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-                       printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
-                       if (eid & 0x0080) /* L/R Surround channels */
-                               total_channels += 2;
-                       if (eid & 0x0140) /* LFE and Center channels */
-                               total_channels += 2;
-                       printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
-               } else {
-                       printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
-               }
-
-               if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
-                       printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
-                       ac97_release_codec(codec);
-                       break;
-               }
-
-               card->ac97_codec[num_ac97] = codec;
-       }
-
-       /* tune up the primary codec */
-       ac97_tune_hardware(card->pci_dev, ac97_quirks, ac97_quirk);
-
-       /* pick the minimum of channels supported by ICHx or codec(s) */
-       card->channels = (card->channels > total_channels)?total_channels:card->channels;
-
-       return num_ac97;
-}
-
-static void __devinit i810_configure_clocking (void)
-{
-       struct i810_card *card;
-       struct i810_state *state;
-       struct dmabuf *dmabuf;
-       unsigned int i, offset, new_offset;
-       unsigned long flags;
-
-       card = devs;
-       /* We could try to set the clocking for multiple cards, but can you even have
-        * more than one i810 in a machine?  Besides, clocking is global, so unless
-        * someone actually thinks more than one i810 in a machine is possible and
-        * decides to rewrite that little bit, setting the rate for more than one card
-        * is a waste of time.
-        */
-       if(card != NULL) {
-               state = card->states[0] = (struct i810_state *)
-                                       kzalloc(sizeof(struct i810_state), GFP_KERNEL);
-               if (state == NULL)
-                       return;
-               dmabuf = &state->dmabuf;
-
-               dmabuf->write_channel = card->alloc_pcm_channel(card);
-               state->virt = 0;
-               state->card = card;
-               state->magic = I810_STATE_MAGIC;
-               init_waitqueue_head(&dmabuf->wait);
-               mutex_init(&state->open_mutex);
-               dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
-               dmabuf->trigger = PCM_ENABLE_OUTPUT;
-               i810_set_spdif_output(state, -1, 0);
-               i810_set_dac_channels(state, 2);
-               i810_set_dac_rate(state, 48000);
-               if(prog_dmabuf(state, 0) != 0) {
-                       goto config_out_nodmabuf;
-               }
-               if(dmabuf->dmasize < 16384) {
-                       goto config_out;
-               }
-               dmabuf->count = dmabuf->dmasize;
-               CIV_TO_LVI(card, dmabuf->write_channel->port, -1);
-               local_irq_save(flags);
-               start_dac(state);
-               offset = i810_get_dma_addr(state, 0);
-               mdelay(50);
-               new_offset = i810_get_dma_addr(state, 0);
-               stop_dac(state);
-               local_irq_restore(flags);
-               i = new_offset - offset;
-#ifdef DEBUG_INTERRUPTS
-               printk("i810_audio: %d bytes in 50 milliseconds\n", i);
-#endif
-               if(i == 0)
-                       goto config_out;
-               i = i / 4 * 20;
-               if (i > 48500 || i < 47500) {
-                       clocking = clocking * clocking / i;
-                       printk("i810_audio: setting clocking to %d\n", clocking);
-               }
-config_out:
-               dealloc_dmabuf(state);
-config_out_nodmabuf:
-               state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num);
-               kfree(state);
-               card->states[0] = NULL;
-       }
-}
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
-   
-static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
-       struct i810_card *card;
-
-       if (pci_enable_device(pci_dev))
-               return -EIO;
-
-       if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) {
-               printk(KERN_ERR "i810_audio: architecture does not support"
-                      " 32bit PCI busmaster DMA\n");
-               return -ENODEV;
-       }
-       
-       if ((card = kzalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) {
-               printk(KERN_ERR "i810_audio: out of memory\n");
-               return -ENOMEM;
-       }
-
-       card->initializing = 1;
-       card->pci_dev = pci_dev;
-       card->pci_id = pci_id->device;
-       card->ac97base = pci_resource_start (pci_dev, 0);
-       card->iobase = pci_resource_start (pci_dev, 1);
-
-       if (!(card->ac97base) || !(card->iobase)) {
-               card->ac97base = 0;
-               card->iobase = 0;
-       }
-
-       /* if chipset could have mmio capability, check it */ 
-       if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
-               card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
-               card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
-
-               if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
-                       card->use_mmio = 1;
-               }
-               else {
-                       card->ac97base_mmio_phys = 0;
-                       card->iobase_mmio_phys = 0;
-               }
-       }
-
-       if (!(card->use_mmio) && (!(card->iobase) || !(card->ac97base))) {
-               printk(KERN_ERR "i810_audio: No I/O resources available.\n");
-               goto out_mem;
-       }
-
-       card->irq = pci_dev->irq;
-       card->next = devs;
-       card->magic = I810_CARD_MAGIC;
-#ifdef CONFIG_PM
-       card->pm_suspended=0;
-#endif
-       spin_lock_init(&card->lock);
-       spin_lock_init(&card->ac97_lock);
-       devs = card;
-
-       pci_set_master(pci_dev);
-
-       printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
-              "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
-              card_names[pci_id->driver_data], 
-              card->iobase, card->ac97base, 
-              card->ac97base_mmio_phys, card->iobase_mmio_phys,
-              card->irq);
-
-       card->alloc_pcm_channel = i810_alloc_pcm_channel;
-       card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
-       card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
-       card->free_pcm_channel = i810_free_pcm_channel;
-
-       if ((card->channel = pci_alloc_consistent(pci_dev,
-           sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
-               printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
-               goto out_mem;
-       }
-
-       { /* We may dispose of this altogether some time soon, so... */
-               struct i810_channel *cp = card->channel;
-
-               cp[0].offset = 0;
-               cp[0].port = 0x00;
-               cp[0].num = 0;
-               cp[1].offset = 0;
-               cp[1].port = 0x10;
-               cp[1].num = 1;
-               cp[2].offset = 0;
-               cp[2].port = 0x20;
-               cp[2].num = 2;
-       }
-
-       /* claim our iospace and irq */
-       if (!request_region(card->iobase, 64, card_names[pci_id->driver_data])) {
-               printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->iobase);
-               goto out_region1;
-       }
-       if (!request_region(card->ac97base, 256, card_names[pci_id->driver_data])) {
-               printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->ac97base);
-               goto out_region2;
-       }
-
-       if (card->use_mmio) {
-               if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
-                       if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
-                               if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
-                                       if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
-                                               printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
-                                                      card_names[pci_id->driver_data], 
-                                                      (unsigned long) card->ac97base_mmio, 
-                                                      (unsigned long) card->iobase_mmio); 
-                                       }
-                                       else {
-                                               iounmap(card->ac97base_mmio);
-                                               release_mem_region(card->ac97base_mmio_phys, 512);
-                                               release_mem_region(card->iobase_mmio_phys, 512);
-                                               card->use_mmio = 0;
-                                       }
-                               }
-                               else {
-                                       iounmap(card->ac97base_mmio);
-                                       release_mem_region(card->ac97base_mmio_phys, 512);
-                                       card->use_mmio = 0;
-                               }
-                       }
-               }
-               else {
-                       card->use_mmio = 0;
-               }
-       }
-
-       /* initialize AC97 codec and register /dev/mixer */
-       if (i810_ac97_init(card) <= 0)
-               goto out_iospace;
-       pci_set_drvdata(pci_dev, card);
-
-       if(clocking == 0) {
-               clocking = 48000;
-               i810_configure_clocking();
-       }
-
-       /* register /dev/dsp */
-       if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
-               int i;
-               printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
-               for (i = 0; i < NR_AC97; i++)
-               if (card->ac97_codec[i] != NULL) {
-                       unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
-                       ac97_release_codec(card->ac97_codec[i]);
-               }
-               goto out_iospace;
-       }
-
-       if (request_irq(card->irq, &i810_interrupt, IRQF_SHARED,
-                       card_names[pci_id->driver_data], card)) {
-               printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
-               goto out_iospace;
-       }
-
-
-       card->initializing = 0;
-       return 0;
-
-out_iospace:
-       if (card->use_mmio) {
-               iounmap(card->ac97base_mmio);
-               iounmap(card->iobase_mmio);
-               release_mem_region(card->ac97base_mmio_phys, 512);
-               release_mem_region(card->iobase_mmio_phys, 256);
-       }
-       release_region(card->ac97base, 256);
-out_region2:
-       release_region(card->iobase, 64);
-out_region1:
-       pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
-           card->channel, card->chandma);
-out_mem:
-       kfree(card);
-       return -ENODEV;
-}
-
-static void __devexit i810_remove(struct pci_dev *pci_dev)
-{
-       int i;
-       struct i810_card *card = pci_get_drvdata(pci_dev);
-       /* free hardware resources */
-       free_irq(card->irq, devs);
-       release_region(card->iobase, 64);
-       release_region(card->ac97base, 256);
-       pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
-                           card->channel, card->chandma);
-       if (card->use_mmio) {
-               iounmap(card->ac97base_mmio);
-               iounmap(card->iobase_mmio);
-               release_mem_region(card->ac97base_mmio_phys, 512);
-               release_mem_region(card->iobase_mmio_phys, 256);
-       }
-
-       /* unregister audio devices */
-       for (i = 0; i < NR_AC97; i++)
-               if (card->ac97_codec[i] != NULL) {
-                       unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
-                       ac97_release_codec(card->ac97_codec[i]);
-                       card->ac97_codec[i] = NULL;
-               }
-       unregister_sound_dsp(card->dev_audio);
-       kfree(card);
-}
-
-#ifdef CONFIG_PM
-static int i810_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
-{
-        struct i810_card *card = pci_get_drvdata(dev);
-        struct i810_state *state;
-       unsigned long flags;
-       struct dmabuf *dmabuf;
-       int i,num_ac97;
-#ifdef DEBUG
-       printk("i810_audio: i810_pm_suspend called\n");
-#endif
-       if(!card) return 0;
-       spin_lock_irqsave(&card->lock, flags);
-       card->pm_suspended=1;
-       for(i=0;i<NR_HW_CH;i++) {
-               state = card->states[i];
-               if(!state) continue;
-               /* this happens only if there are open files */
-               dmabuf = &state->dmabuf;
-               if(dmabuf->enable & DAC_RUNNING ||
-                  (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
-                       state->pm_saved_dac_rate=dmabuf->rate;
-                       stop_dac(state);
-               } else {
-                       state->pm_saved_dac_rate=0;
-               }
-               if(dmabuf->enable & ADC_RUNNING) {
-                       state->pm_saved_adc_rate=dmabuf->rate;  
-                       stop_adc(state);
-               } else {
-                       state->pm_saved_adc_rate=0;
-               }
-               dmabuf->ready = 0;
-               dmabuf->swptr = dmabuf->hwptr = 0;
-               dmabuf->count = dmabuf->total_bytes = 0;
-       }
-
-       spin_unlock_irqrestore(&card->lock, flags);
-
-       /* save mixer settings */
-       for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-               struct ac97_codec *codec = card->ac97_codec[num_ac97];
-               if(!codec) continue;
-               for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
-                       if((supported_mixer(codec,i)) &&
-                          (codec->read_mixer)) {
-                               card->pm_saved_mixer_settings[i][num_ac97]=
-                                       codec->read_mixer(codec,i);
-                       }
-               }
-       }
-       pci_save_state(dev); /* XXX do we need this? */
-       pci_disable_device(dev); /* disable busmastering */
-       pci_set_power_state(dev,3); /* Zzz. */
-
-       return 0;
-}
-
-
-static int i810_pm_resume(struct pci_dev *dev)
-{
-       int num_ac97,i=0;
-       struct i810_card *card=pci_get_drvdata(dev);
-       pci_enable_device(dev);
-       pci_restore_state (dev);
-
-       /* observation of a toshiba portege 3440ct suggests that the 
-          hardware has to be more or less completely reinitialized from
-          scratch after an apm suspend.  Works For Me.   -dan */
-
-       i810_ac97_power_up_bus(card);
-
-       for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-               struct ac97_codec *codec = card->ac97_codec[num_ac97];
-               /* check they haven't stolen the hardware while we were
-                  away */
-               if(!codec || !i810_ac97_exists(card,num_ac97)) {
-                       if(num_ac97) continue;
-                       else BUG();
-               }
-               if(!i810_ac97_probe_and_powerup(card,codec)) BUG();
-               
-               if((card->ac97_features&0x0001)) {
-                       /* at probe time we found we could do variable
-                          rates, but APM suspend has made it forget
-                          its magical powers */
-                       if(!i810_ac97_enable_variable_rate(codec)) BUG();
-               }
-               /* we lost our mixer settings, so restore them */
-               for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) {
-                       if(supported_mixer(codec,i)){
-                               int val=card->
-                                       pm_saved_mixer_settings[i][num_ac97];
-                               codec->mixer_state[i]=val;
-                               codec->write_mixer(codec,i,
-                                                  (val  & 0xff) ,
-                                                  ((val >> 8)  & 0xff) );
-                       }
-               }
-       }
-
-       /* we need to restore the sample rate from whatever it was */
-       for(i=0;i<NR_HW_CH;i++) {
-               struct i810_state * state=card->states[i];
-               if(state) {
-                       if(state->pm_saved_adc_rate)
-                               i810_set_adc_rate(state,state->pm_saved_adc_rate);
-                       if(state->pm_saved_dac_rate)
-                               i810_set_dac_rate(state,state->pm_saved_dac_rate);
-               }
-       }
-
-       
-        card->pm_suspended = 0;
-
-       /* any processes that were reading/writing during the suspend
-          probably ended up here */
-       for(i=0;i<NR_HW_CH;i++) {
-               struct i810_state *state = card->states[i];
-               if(state) wake_up(&state->dmabuf.wait);
-        }
-
-       return 0;
-}      
-#endif /* CONFIG_PM */
-
-MODULE_AUTHOR("The Linux kernel team");
-MODULE_DESCRIPTION("Intel 810 audio support");
-MODULE_LICENSE("GPL");
-module_param(ftsodell, int, 0444);
-module_param(clocking, uint, 0444);
-module_param(strict_clocking, int, 0444);
-module_param(spdif_locked, int, 0444);
-
-#define I810_MODULE_NAME "i810_audio"
-
-static struct pci_driver i810_pci_driver = {
-       .name           = I810_MODULE_NAME,
-       .id_table       = i810_pci_tbl,
-       .probe          = i810_probe,
-       .remove         = __devexit_p(i810_remove),
-#ifdef CONFIG_PM
-       .suspend        = i810_pm_suspend,
-       .resume         = i810_pm_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init i810_init_module (void)
-{
-       int retval;
-
-       printk(KERN_INFO "Intel 810 + AC97 Audio, version "
-              DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
-       retval = pci_register_driver(&i810_pci_driver);
-       if (retval)
-               return retval;
-
-       if(ftsodell != 0) {
-               printk("i810_audio: ftsodell is now a deprecated option.\n");
-       }
-       if(spdif_locked > 0 ) {
-               if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
-                       printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
-               } else {
-                       printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
-                       spdif_locked = 0;
-               }
-       }
-       
-       return 0;
-}
-
-static void __exit i810_cleanup_module (void)
-{
-       pci_unregister_driver(&i810_pci_driver);
-}
-
-module_init(i810_init_module);
-module_exit(i810_cleanup_module);
-
-/*
-Local Variables:
-c-basic-offset: 8
-End:
-*/
index ece428b..16ed069 100644 (file)
@@ -232,14 +232,12 @@ static int set_irq(pss_confdata * devc, int dev, int irq)
        return 1;
 }
 
-static int set_io_base(pss_confdata * devc, int dev, int base)
+static void set_io_base(pss_confdata * devc, int dev, int base)
 {
        unsigned short  tmp = inw(REG(dev)) & 0x003f;
        unsigned short  bits = (base & 0x0ffc) << 4;
 
        outw(bits | tmp, REG(dev));
-
-       return 1;
 }
 
 static int set_dma(pss_confdata * devc, int dev, int dma)
@@ -673,20 +671,12 @@ static void configure_nonsound_components(void)
 
        /* Configure CDROM port */
 
-       if(pss_cdrom_port == -1)        /* If cdrom port enablation wasn't requested */
-       {
+       if (pss_cdrom_port == -1) {     /* If cdrom port enablation wasn't requested */
                printk(KERN_INFO "PSS: CDROM port not enabled.\n");
-       }
-       else if(check_region(pss_cdrom_port, 2))
-       {
+       } else if (check_region(pss_cdrom_port, 2)) {
                printk(KERN_ERR "PSS: CDROM I/O port conflict.\n");
-       }
-       else if(!set_io_base(devc, CONF_CDROM, pss_cdrom_port))
-       {
-               printk(KERN_ERR "PSS: CDROM I/O port could not be set.\n");
-       }
-       else                                    /* CDROM port successfully configured */
-       {
+       } else {
+               set_io_base(devc, CONF_CDROM, pss_cdrom_port);
                printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port);
        }
 }
@@ -758,10 +748,7 @@ static int __init probe_pss_mpu(struct address_info *hw_config)
                printk(KERN_ERR "PSS: MPU I/O port conflict\n");
                return 0;
        }
-       if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) {
-               printk(KERN_ERR "PSS: MIDI base could not be set.\n");
-               goto fail;
-       }
+       set_io_base(devc, CONF_MIDI, hw_config->io_base);
        if (!set_irq(devc, CONF_MIDI, hw_config->irq)) {
                printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n");
                goto fail;
@@ -1057,10 +1044,7 @@ static int __init probe_pss_mss(struct address_info *hw_config)
                release_region(hw_config->io_base, 4);
                return 0;
        }
-       if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) {
-               printk("PSS: WSS base not settable.\n");
-               goto fail;
-       }
+       set_io_base(devc, CONF_WSS, hw_config->io_base);
        if (!set_irq(devc, CONF_WSS, hw_config->irq)) {
                printk("PSS: WSS IRQ allocation error.\n");
                goto fail;
index 07cbacf..77d0e5e 100644 (file)
@@ -1228,7 +1228,8 @@ int probe_sbmpu(struct address_info *hw_config, struct module *owner)
                }
                attach_mpu401(hw_config, owner);
                if (last_sb->irq == -hw_config->irq)
-                       last_sb->midi_irq_cookie=(void *)hw_config->slots[1];
+                       last_sb->midi_irq_cookie =
+                               (void *)(long) hw_config->slots[1];
                return 1;
        }
 #endif
index 96adc47..6959ee1 100644 (file)
@@ -2935,7 +2935,7 @@ trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
        do {
                if ((inw(TRID_REG(card, address)) & busy) == 0)
                        break;
-       } while (count--);
+       } while (--count);
 
        data |= (mask | (reg & AC97_REG_ADDR));
 
@@ -2996,7 +2996,7 @@ trident_ac97_get(struct ac97_codec *codec, u8 reg)
                data = inl(TRID_REG(card, address));
                if ((data & busy) == 0)
                        break;
-       } while (count--);
+       } while (--count);
        spin_unlock_irqrestore(&card->lock, flags);
 
        if (count == 0) {
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
deleted file mode 100644 (file)
index f95aa09..0000000
+++ /dev/null
@@ -1,3616 +0,0 @@
-/*
- * Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999,2000 Jeff Garzik
- *
- * Updated to support the VIA 8233/8235 audio subsystem
- * Alan Cox <alan@redhat.com> (C) Copyright 2002, 2003 Red Hat Inc
- *
- * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
- * See the "COPYING" file distributed with this software for more info.
- * NO WARRANTY
- *
- * For a list of known bugs (errata) and documentation,
- * see via-audio.pdf in Documentation/DocBook.
- * If this documentation does not exist, run "make pdfdocs".
- */
-
-
-#define VIA_VERSION    "1.9.1-ac4-2.5"
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/poison.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/sound.h>
-#include <linux/poll.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/mutex.h>
-
-#include "sound_config.h"
-#include "dev_table.h"
-#include "mpu401.h"
-
-
-#undef VIA_DEBUG       /* define to enable debugging output and checks */
-#ifdef VIA_DEBUG
-/* note: prints function name for you */
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#undef VIA_NDEBUG      /* define to disable lightweight runtime checks */
-#ifdef VIA_NDEBUG
-#define assert(expr)
-#else
-#define assert(expr) \
-        if(!(expr)) {                                  \
-        printk( "Assertion failed! %s,%s,%s,line=%d\n",        \
-        #expr,__FILE__,__FUNCTION__,__LINE__);         \
-        }
-#endif
-
-#define VIA_SUPPORT_MMAP 1 /* buggy, for now... */
-
-#define MAX_CARDS      1
-
-#define VIA_CARD_NAME  "VIA 82Cxxx Audio driver " VIA_VERSION
-#define VIA_MODULE_NAME "via82cxxx"
-#define PFX            VIA_MODULE_NAME ": "
-
-#define VIA_COUNTER_LIMIT      100000
-
-/* size of DMA buffers */
-#define VIA_MAX_BUFFER_DMA_PAGES       32
-
-/* buffering default values in ms */
-#define VIA_DEFAULT_FRAG_TIME          20
-#define VIA_DEFAULT_BUFFER_TIME                500
-
-/* the hardware has a 256 fragment limit */
-#define VIA_MIN_FRAG_NUMBER            2
-#define VIA_MAX_FRAG_NUMBER            128
-
-#define VIA_MAX_FRAG_SIZE              PAGE_SIZE
-#define VIA_MIN_FRAG_SIZE              (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE / VIA_MAX_FRAG_NUMBER)
-
-
-/* 82C686 function 5 (audio codec) PCI configuration registers */
-#define VIA_ACLINK_STATUS      0x40
-#define VIA_ACLINK_CTRL                0x41
-#define VIA_FUNC_ENABLE                0x42
-#define VIA_PNP_CONTROL                0x43
-#define VIA_FM_NMI_CTRL                0x48
-
-/*
- * controller base 0 (scatter-gather) registers
- *
- * NOTE: Via datasheet lists first channel as "read"
- * channel and second channel as "write" channel.
- * I changed the naming of the constants to be more
- * clear than I felt the datasheet to be.
- */
-
-#define VIA_BASE0_PCM_OUT_CHAN 0x00 /* output PCM to user */
-#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
-#define VIA_BASE0_PCM_OUT_CHAN_CTRL    0x01
-#define VIA_BASE0_PCM_OUT_CHAN_TYPE    0x02
-
-#define VIA_BASE0_PCM_IN_CHAN          0x10 /* input PCM from user */
-#define VIA_BASE0_PCM_IN_CHAN_STATUS   0x10
-#define VIA_BASE0_PCM_IN_CHAN_CTRL     0x11
-#define VIA_BASE0_PCM_IN_CHAN_TYPE     0x12
-
-/* offsets from base */
-#define VIA_PCM_STATUS                 0x00
-#define VIA_PCM_CONTROL                        0x01
-#define VIA_PCM_TYPE                   0x02
-#define VIA_PCM_LEFTVOL                        0x02
-#define VIA_PCM_RIGHTVOL               0x03
-#define VIA_PCM_TABLE_ADDR             0x04
-#define VIA_PCM_STOPRATE               0x08    /* 8233+ */
-#define VIA_PCM_BLOCK_COUNT            0x0C
-
-/* XXX unused DMA channel for FM PCM data */
-#define VIA_BASE0_FM_OUT_CHAN          0x20
-#define VIA_BASE0_FM_OUT_CHAN_STATUS   0x20
-#define VIA_BASE0_FM_OUT_CHAN_CTRL     0x21
-#define VIA_BASE0_FM_OUT_CHAN_TYPE     0x22
-
-/* Six channel audio output on 8233 */
-#define VIA_BASE0_MULTI_OUT_CHAN               0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_STATUS                0x40
-#define VIA_BASE0_MULTI_OUT_CHAN_CTRL          0x41
-#define VIA_BASE0_MULTI_OUT_CHAN_TYPE          0x42
-
-#define VIA_BASE0_AC97_CTRL            0x80
-#define VIA_BASE0_SGD_STATUS_SHADOW    0x84
-#define VIA_BASE0_GPI_INT_ENABLE       0x8C
-#define VIA_INTR_OUT                   ((1<<0) |  (1<<4) |  (1<<8))
-#define VIA_INTR_IN                    ((1<<1) |  (1<<5) |  (1<<9))
-#define VIA_INTR_FM                    ((1<<2) |  (1<<6) | (1<<10))
-#define VIA_INTR_MASK          (VIA_INTR_OUT | VIA_INTR_IN | VIA_INTR_FM)
-
-/* Newer VIA we need to monitor the low 3 bits of each channel. This
-   mask covers the channels we don't yet use as well 
- */
-#define VIA_NEW_INTR_MASK              0x77077777UL
-
-/* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */
-#define VIA_IRQ_ON_FLAG                        (1<<0)  /* int on each flagged scatter block */
-#define VIA_IRQ_ON_EOL                 (1<<1)  /* int at end of scatter list */
-#define VIA_INT_SEL_PCI_LAST_LINE_READ (0)     /* int at PCI read of last line */
-#define VIA_INT_SEL_LAST_SAMPLE_SENT   (1<<2)  /* int at last sample sent */
-#define VIA_INT_SEL_ONE_LINE_LEFT      (1<<3)  /* int at less than one line to send */
-#define VIA_PCM_FMT_STEREO             (1<<4)  /* PCM stereo format (bit clear == mono) */
-#define VIA_PCM_FMT_16BIT              (1<<5)  /* PCM 16-bit format (bit clear == 8-bit) */
-#define VIA_PCM_REC_FIFO               (1<<6)  /* PCM Recording FIFO */
-#define VIA_RESTART_SGD_ON_EOL         (1<<7)  /* restart scatter-gather at EOL */
-#define VIA_PCM_FMT_MASK               (VIA_PCM_FMT_STEREO|VIA_PCM_FMT_16BIT)
-#define VIA_CHAN_TYPE_MASK             (VIA_RESTART_SGD_ON_EOL | \
-                                        VIA_IRQ_ON_FLAG | \
-                                        VIA_IRQ_ON_EOL)
-#define VIA_CHAN_TYPE_INT_SELECT       (VIA_INT_SEL_LAST_SAMPLE_SENT)
-
-/* PCI configuration register bits and masks */
-#define VIA_CR40_AC97_READY    0x01
-#define VIA_CR40_AC97_LOW_POWER        0x02
-#define VIA_CR40_SECONDARY_READY 0x04
-
-#define VIA_CR41_AC97_ENABLE   0x80 /* enable AC97 codec */
-#define VIA_CR41_AC97_RESET    0x40 /* clear bit to reset AC97 */
-#define VIA_CR41_AC97_WAKEUP   0x20 /* wake up from power-down mode */
-#define VIA_CR41_AC97_SDO      0x10 /* force Serial Data Out (SDO) high */
-#define VIA_CR41_VRA           0x08 /* enable variable sample rate */
-#define VIA_CR41_PCM_ENABLE    0x04 /* AC Link SGD Read Channel PCM Data Output */
-#define VIA_CR41_FM_PCM_ENABLE 0x02 /* AC Link FM Channel PCM Data Out */
-#define VIA_CR41_SB_PCM_ENABLE 0x01 /* AC Link SB PCM Data Output */
-#define VIA_CR41_BOOT_MASK     (VIA_CR41_AC97_ENABLE | \
-                                VIA_CR41_AC97_WAKEUP | \
-                                VIA_CR41_AC97_SDO)
-#define VIA_CR41_RUN_MASK      (VIA_CR41_AC97_ENABLE | \
-                                VIA_CR41_AC97_RESET | \
-                                VIA_CR41_VRA | \
-                                VIA_CR41_PCM_ENABLE)
-
-#define VIA_CR42_SB_ENABLE     0x01
-#define VIA_CR42_MIDI_ENABLE   0x02
-#define VIA_CR42_FM_ENABLE     0x04
-#define VIA_CR42_GAME_ENABLE   0x08
-#define VIA_CR42_MIDI_IRQMASK   0x40
-#define VIA_CR42_MIDI_PNP      0x80
-
-#define VIA_CR44_SECOND_CODEC_SUPPORT  (1 << 6)
-#define VIA_CR44_AC_LINK_ACCESS                (1 << 7)
-
-#define VIA_CR48_FM_TRAP_TO_NMI                (1 << 2)
-
-/* controller base 0 register bitmasks */
-#define VIA_INT_DISABLE_MASK           (~(0x01|0x02))
-#define VIA_SGD_STOPPED                        (1 << 2)
-#define VIA_SGD_PAUSED                 (1 << 6)
-#define VIA_SGD_ACTIVE                 (1 << 7)
-#define VIA_SGD_TERMINATE              (1 << 6)
-#define VIA_SGD_FLAG                   (1 << 0)
-#define VIA_SGD_EOL                    (1 << 1)
-#define VIA_SGD_START                  (1 << 7)
-
-#define VIA_CR80_FIRST_CODEC           0
-#define VIA_CR80_SECOND_CODEC          (1 << 30)
-#define VIA_CR80_FIRST_CODEC_VALID     (1 << 25)
-#define VIA_CR80_VALID                 (1 << 25)
-#define VIA_CR80_SECOND_CODEC_VALID    (1 << 27)
-#define VIA_CR80_BUSY                  (1 << 24)
-#define VIA_CR83_BUSY                  (1)
-#define VIA_CR83_FIRST_CODEC_VALID     (1 << 1)
-#define VIA_CR80_READ                  (1 << 23)
-#define VIA_CR80_WRITE_MODE            0
-#define VIA_CR80_REG_IDX(idx)          ((((idx) & 0xFF) >> 1) << 16)
-
-/* capabilities we announce */
-#ifdef VIA_SUPPORT_MMAP
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | DSP_CAP_MMAP | \
-                    DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#else
-#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | \
-                    DSP_CAP_TRIGGER | DSP_CAP_REALTIME)
-#endif
-
-/* scatter-gather DMA table entry, exactly as passed to hardware */
-struct via_sgd_table {
-       u32 addr;
-       u32 count;      /* includes additional VIA_xxx bits also */
-};
-
-#define VIA_EOL (1 << 31)
-#define VIA_FLAG (1 << 30)
-#define VIA_STOP (1 << 29)
-
-
-enum via_channel_states {
-       sgd_stopped = 0,
-       sgd_in_progress = 1,
-};
-
-
-struct via_buffer_pgtbl {
-       dma_addr_t handle;
-       void *cpuaddr;
-};
-
-
-struct via_channel {
-       atomic_t n_frags;
-       atomic_t hw_ptr;
-       wait_queue_head_t wait;
-
-       unsigned int sw_ptr;
-       unsigned int slop_len;
-       unsigned int n_irqs;
-       int bytes;
-
-       unsigned is_active : 1;
-       unsigned is_record : 1;
-       unsigned is_mapped : 1;
-       unsigned is_enabled : 1;
-       unsigned is_multi: 1;   /* 8233 6 channel */
-       u8 pcm_fmt;             /* VIA_PCM_FMT_xxx */
-       u8 channels;            /* Channel count */
-
-       unsigned rate;          /* sample rate */
-       unsigned int frag_size;
-       unsigned int frag_number;
-       
-       unsigned char intmask;
-
-       volatile struct via_sgd_table *sgtable;
-       dma_addr_t sgt_handle;
-
-       unsigned int page_number;
-       struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES];
-
-       long iobase;
-
-       const char *name;
-};
-
-
-/* data stored for each chip */
-struct via_info {
-       struct pci_dev *pdev;
-       long baseaddr;
-
-       struct ac97_codec *ac97;
-       spinlock_t ac97_lock;
-       spinlock_t lock;
-       int card_num;           /* unique card number, from 0 */
-
-       int dev_dsp;            /* /dev/dsp index from register_sound_dsp() */
-
-       unsigned rev_h : 1;
-       unsigned legacy: 1;     /* Has legacy ports */
-       unsigned intmask: 1;    /* Needs int bits */
-       unsigned sixchannel: 1; /* 8233/35 with 6 channel support */
-       unsigned volume: 1;
-
-       unsigned locked_rate : 1;
-       
-       int mixer_vol;          /* 8233/35 volume  - not yet implemented */
-
-       struct mutex syscall_mutex;
-       struct mutex open_mutex;
-
-       /* The 8233/8235 have 4 DX audio channels, two record and
-          one six channel out. We bind ch_in to DX 1, ch_out to multichannel
-          and ch_fm to DX 2. DX 3 and REC0/REC1 are unused at the
-          moment */
-          
-       struct via_channel ch_in;
-       struct via_channel ch_out;
-       struct via_channel ch_fm;
-
-#ifdef CONFIG_MIDI_VIA82CXXX
-        void *midi_devc;
-        struct address_info midi_info;
-#endif
-};
-
-
-/* number of cards, used for assigning unique numbers to cards */
-static unsigned via_num_cards;
-
-
-
-/****************************************************************
- *
- * prototypes
- *
- *
- */
-
-static int via_init_one (struct pci_dev *dev, const struct pci_device_id *id);
-static void __devexit via_remove_one (struct pci_dev *pdev);
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait);
-static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int via_dsp_open (struct inode *inode, struct file *file);
-static int via_dsp_release(struct inode *inode, struct file *file);
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma);
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg);
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value);
-static u8 via_ac97_wait_idle (struct via_info *card);
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan);
-static void via_chan_clear (struct via_info *card, struct via_channel *chan);
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset);
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan);
-
-
-/****************************************************************
- *
- * Various data the driver needs
- *
- *
- */
-
-
-static struct pci_device_id via_pci_tbl[] = {
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-       { 0, }
-};
-MODULE_DEVICE_TABLE(pci,via_pci_tbl);
-
-
-static struct pci_driver via_driver = {
-       .name           = VIA_MODULE_NAME,
-       .id_table       = via_pci_tbl,
-       .probe          = via_init_one,
-       .remove         = __devexit_p(via_remove_one),
-};
-
-
-/****************************************************************
- *
- * Low-level base 0 register read/write helpers
- *
- *
- */
-
-/**
- *     via_chan_stop - Terminate DMA on specified PCM channel
- *     @iobase: PCI base address for SGD channel registers
- *
- *     Terminate scatter-gather DMA operation for given
- *     channel (derived from @iobase), if DMA is active.
- *
- *     Note that @iobase is not the PCI base address,
- *     but the PCI base address plus an offset to
- *     one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_stop (long iobase)
-{
-       if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE)
-               outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL);
-}
-
-
-/**
- *     via_chan_status_clear - Clear status flags on specified DMA channel
- *     @iobase: PCI base address for SGD channel registers
- *
- *     Clear any pending status flags for the given
- *     DMA channel (derived from @iobase), if any
- *     flags are asserted.
- *
- *     Note that @iobase is not the PCI base address,
- *     but the PCI base address plus an offset to
- *     one of three PCM channels supported by the chip.
- *
- */
-
-static inline void via_chan_status_clear (long iobase)
-{
-       u8 tmp = inb (iobase + VIA_PCM_STATUS);
-
-       if (tmp != 0)
-               outb (tmp, iobase + VIA_PCM_STATUS);
-}
-
-
-/**
- *     sg_begin - Begin recording or playback on a PCM channel
- *     @chan: Channel for which DMA operation shall begin
- *
- *     Start scatter-gather DMA for the given channel.
- *
- */
-
-static inline void sg_begin (struct via_channel *chan)
-{
-       DPRINTK("Start with intmask %d\n", chan->intmask);
-       DPRINTK("About to start from %d to %d\n", 
-               inl(chan->iobase + VIA_PCM_BLOCK_COUNT),
-               inb(chan->iobase + VIA_PCM_STOPRATE + 3));
-       outb (VIA_SGD_START|chan->intmask, chan->iobase + VIA_PCM_CONTROL);
-       DPRINTK("Status is now %02X\n", inb(chan->iobase + VIA_PCM_STATUS));
-       DPRINTK("Control is now %02X\n", inb(chan->iobase + VIA_PCM_CONTROL));
-}
-
-
-static int sg_active (long iobase)
-{
-       u8 tmp = inb (iobase + VIA_PCM_STATUS);
-       if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) {
-               printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n");
-               return 0;
-       }
-       if (tmp & VIA_SGD_ACTIVE)
-               return 1;
-       return 0;
-}
-
-static int via_sg_offset(struct via_channel *chan)
-{
-       return inl (chan->iobase + VIA_PCM_BLOCK_COUNT) & 0x00FFFFFF;
-}
-
-/****************************************************************
- *
- * Miscellaneous debris
- *
- *
- */
-
-
-/**
- *     via_syscall_down - down the card-specific syscell semaphore
- *     @card: Private info for specified board
- *     @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- *     Encapsulates standard method of acquiring the syscall sem.
- *
- *     Returns negative errno on error, or zero for success.
- */
-
-static inline int via_syscall_down (struct via_info *card, int nonblock)
-{
-       /* Thomas Sailer:
-        * EAGAIN is supposed to be used if IO is pending,
-        * not if there is contention on some internal
-        * synchronization primitive which should be
-        * held only for a short time anyway
-        */
-       nonblock = 0;
-
-       if (nonblock) {
-               if (!mutex_trylock(&card->syscall_mutex))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&card->syscall_mutex))
-                       return -ERESTARTSYS;
-       }
-
-       return 0;
-}
-
-
-/**
- *     via_stop_everything - Stop all audio operations
- *     @card: Private info for specified board
- *
- *     Stops all DMA operations and interrupts, and clear
- *     any pending status bits resulting from those operations.
- */
-
-static void via_stop_everything (struct via_info *card)
-{
-       u8 tmp, new_tmp;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-
-       /*
-        * terminate any existing operations on audio read/write channels
-        */
-       via_chan_stop (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
-       via_chan_stop (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
-       via_chan_stop (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-       if(card->sixchannel)
-               via_chan_stop (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
-       /*
-        * clear any existing stops / flags (sanity check mainly)
-        */
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-       if(card->sixchannel)
-               via_chan_status_clear (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
-
-       /*
-        * clear any enabled interrupt bits
-        */
-       tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
-       new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-       if (tmp != new_tmp)
-               outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE);
-
-       tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
-       new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-       if (tmp != new_tmp)
-               outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE);
-
-       tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
-       new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-       if (tmp != new_tmp)
-               outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
-
-       if(card->sixchannel)
-       {
-               tmp = inb (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
-               new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
-               if (tmp != new_tmp)
-                       outb (0, card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
-       }
-
-       udelay(10);
-
-       /*
-        * clear any existing flags
-        */
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
-       via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-/**
- *     via_set_rate - Set PCM rate for given channel
- *     @ac97: Pointer to generic codec info struct
- *     @chan: Private info for specified channel
- *     @rate: Desired PCM sample rate, in Khz
- *
- *     Sets the PCM sample rate for a channel.
- *
- *     Values for @rate are clamped to a range of 4000 Khz through 48000 Khz,
- *     due to hardware constraints.
- */
-
-static int via_set_rate (struct ac97_codec *ac97,
-                        struct via_channel *chan, unsigned rate)
-{
-       struct via_info *card = ac97->private_data;
-       int rate_reg;
-       u32 dacp;
-       u32 mast_vol, phone_vol, mono_vol, pcm_vol;
-       u32 mute_vol = 0x8000;  /* The mute volume? -- Seems to work! */
-
-       DPRINTK ("ENTER, rate = %d\n", rate);
-
-       if (chan->rate == rate)
-               goto out;
-       if (card->locked_rate) {
-               chan->rate = 48000;
-               goto out;
-       }
-
-       if (rate > 48000)               rate = 48000;
-       if (rate < 4000)                rate = 4000;
-
-       rate_reg = chan->is_record ? AC97_PCM_LR_ADC_RATE :
-                           AC97_PCM_FRONT_DAC_RATE;
-
-       /* Save current state */
-       dacp=via_ac97_read_reg(ac97, AC97_POWER_CONTROL);
-       mast_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_STEREO);
-       mono_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_MONO);
-       phone_vol = via_ac97_read_reg(ac97, AC97_HEADPHONE_VOL);
-       pcm_vol = via_ac97_read_reg(ac97, AC97_PCMOUT_VOL);
-       /* Mute - largely reduces popping */
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mute_vol);
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mute_vol);
-       via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, mute_vol);
-               via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, mute_vol);
-       /* Power down the DAC */
-       via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp|0x0200);
-
-        /* Set new rate */
-       via_ac97_write_reg (ac97, rate_reg, rate);
-
-       /* Power DAC back up */
-       via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp);
-       udelay (200); /* reduces popping */
-
-       /* Restore volumes */
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mast_vol);
-       via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mono_vol);
-       via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, phone_vol);
-       via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, pcm_vol);
-
-       /* the hardware might return a value different than what we
-        * passed to it, so read the rate value back from hardware
-        * to see what we came up with
-        */
-       chan->rate = via_ac97_read_reg (ac97, rate_reg);
-
-       if (chan->rate == 0) {
-               card->locked_rate = 1;
-               chan->rate = 48000;
-               printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
-       }
-
-out:
-       DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate);
-       return chan->rate;
-}
-
-
-/****************************************************************
- *
- * Channel-specific operations
- *
- *
- */
-
-
-/**
- *     via_chan_init_defaults - Initialize a struct via_channel
- *     @card: Private audio chip info
- *     @chan: Channel to be initialized
- *
- *     Zero @chan, and then set all static defaults for the structure.
- */
-
-static void via_chan_init_defaults (struct via_info *card, struct via_channel *chan)
-{
-       memset (chan, 0, sizeof (*chan));
-
-       if(card->intmask)
-               chan->intmask = 0x23;   /* Turn on the IRQ bits */
-               
-       if (chan == &card->ch_out) {
-               chan->name = "PCM-OUT";
-               if(card->sixchannel)
-               {
-                       chan->iobase = card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN;
-                       chan->is_multi = 1;
-                       DPRINTK("Using multichannel for pcm out\n");
-               }
-               else
-                       chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN;
-       } else if (chan == &card->ch_in) {
-               chan->name = "PCM-IN";
-               chan->iobase = card->baseaddr + VIA_BASE0_PCM_IN_CHAN;
-               chan->is_record = 1;
-       } else if (chan == &card->ch_fm) {
-               chan->name = "PCM-OUT-FM";
-               chan->iobase = card->baseaddr + VIA_BASE0_FM_OUT_CHAN;
-       } else {
-               BUG();
-       }
-
-       init_waitqueue_head (&chan->wait);
-
-       chan->pcm_fmt = VIA_PCM_FMT_MASK;
-       chan->is_enabled = 1;
-
-       chan->frag_number = 0;
-        chan->frag_size = 0;
-       atomic_set(&chan->n_frags, 0);
-       atomic_set (&chan->hw_ptr, 0);
-}
-
-/**
- *      via_chan_init - Initialize PCM channel
- *      @card: Private audio chip info
- *      @chan: Channel to be initialized
- *
- *      Performs some of the preparations necessary to begin
- *      using a PCM channel.
- *
- *      Currently the preparations consist of
- *      setting the PCM channel to a known state.
- */
-
-
-static void via_chan_init (struct via_info *card, struct via_channel *chan)
-{
-
-        DPRINTK ("ENTER\n");
-
-       /* bzero channel structure, and init members to defaults */
-        via_chan_init_defaults (card, chan);
-
-        /* stop any existing channel output */
-        via_chan_clear (card, chan);
-        via_chan_status_clear (chan->iobase);
-        via_chan_pcm_fmt (chan, 1);
-
-       DPRINTK ("EXIT\n");
-}
-
-/**
- *     via_chan_buffer_init - Initialize PCM channel buffer
- *     @card: Private audio chip info
- *     @chan: Channel to be initialized
- *
- *     Performs some of the preparations necessary to begin
- *     using a PCM channel.
- *
- *     Currently the preparations include allocating the
- *     scatter-gather DMA table and buffers,
- *     and passing the
- *     address of the DMA table to the hardware.
- *
- *     Note that special care is taken when passing the
- *     DMA table address to hardware, because it was found
- *     during driver development that the hardware did not
- *     always "take" the address.
- */
-
-static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan)
-{
-       int page, offset;
-       int i;
-
-       DPRINTK ("ENTER\n");
-
-
-       chan->intmask = 0;
-       if(card->intmask)
-               chan->intmask = 0x23;   /* Turn on the IRQ bits */
-               
-       if (chan->sgtable != NULL) {
-               DPRINTK ("EXIT\n");
-               return 0;
-       }
-
-       /* alloc DMA-able memory for scatter-gather table */
-       chan->sgtable = pci_alloc_consistent (card->pdev,
-               (sizeof (struct via_sgd_table) * chan->frag_number),
-               &chan->sgt_handle);
-       if (!chan->sgtable) {
-               printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");
-               DPRINTK ("EXIT\n");
-               return -ENOMEM;
-       }
-
-       memset ((void*)chan->sgtable, 0,
-               (sizeof (struct via_sgd_table) * chan->frag_number));
-
-       /* alloc DMA-able memory for scatter-gather buffers */
-
-       chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE +
-                           (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0);
-
-       for (i = 0; i < chan->page_number; i++) {
-               chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE,
-                                             &chan->pgtbl[i].handle);
-
-               if (!chan->pgtbl[i].cpuaddr) {
-                       chan->page_number = i;
-                       goto err_out_nomem;
-               }
-
-#ifndef VIA_NDEBUG
-                memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size);
-#endif
-
-#if 1
-                DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n",
-                       i, (long)chan->pgtbl[i].handle,
-                       virt_to_phys(chan->pgtbl[i].cpuaddr),
-                       chan->pgtbl[i].cpuaddr);
-#endif
-       }
-
-       for (i = 0; i < chan->frag_number; i++) {
-
-               page = i / (PAGE_SIZE / chan->frag_size);
-               offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
-               chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
-               chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset);
-
-#if 1
-               DPRINTK ("dmabuf #%d (32(h)=%lx)\n",
-                        i,
-                        (long)chan->sgtable[i].addr);
-#endif
-       }
-
-       /* overwrite the last buffer information */
-       chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
-
-       /* set location of DMA-able scatter-gather info table */
-       DPRINTK ("outl (0x%X, 0x%04lX)\n",
-               chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
-
-       via_ac97_wait_idle (card);
-       outl (chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
-       udelay (20);
-       via_ac97_wait_idle (card);
-       /* load no rate adaption, stereo 16bit, set up ring slots */
-       if(card->sixchannel)
-       {
-               if(!chan->is_multi)
-               {
-                       outl (0xFFFFF | (0x3 << 20) | (chan->frag_number << 24), chan->iobase + VIA_PCM_STOPRATE);
-                       udelay (20);
-                       via_ac97_wait_idle (card);
-               }
-       }
-
-       DPRINTK ("inl (0x%lX) = %x\n",
-               chan->iobase + VIA_PCM_TABLE_ADDR,
-               inl(chan->iobase + VIA_PCM_TABLE_ADDR));
-
-       DPRINTK ("EXIT\n");
-       return 0;
-
-err_out_nomem:
-       printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");
-       via_chan_buffer_free (card, chan);
-       DPRINTK ("EXIT\n");
-       return -ENOMEM;
-}
-
-
-/**
- *     via_chan_free - Release a PCM channel
- *     @card: Private audio chip info
- *     @chan: Channel to be released
- *
- *     Performs all the functions necessary to clean up
- *     an initialized channel.
- *
- *     Currently these functions include disabled any
- *     active DMA operations, setting the PCM channel
- *     back to a known state, and releasing any allocated
- *     sound buffers.
- */
-
-static void via_chan_free (struct via_info *card, struct via_channel *chan)
-{
-       DPRINTK ("ENTER\n");
-
-       spin_lock_irq (&card->lock);
-
-       /* stop any existing channel output */
-       via_chan_status_clear (chan->iobase);
-       via_chan_stop (chan->iobase);
-       via_chan_status_clear (chan->iobase);
-
-       spin_unlock_irq (&card->lock);
-
-       synchronize_irq(card->pdev->irq);
-
-       DPRINTK ("EXIT\n");
-}
-
-static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan)
-{
-       int i;
-
-        DPRINTK ("ENTER\n");
-
-       /* zero location of DMA-able scatter-gather info table */
-       via_ac97_wait_idle(card);
-       outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);
-
-       for (i = 0; i < chan->page_number; i++)
-               if (chan->pgtbl[i].cpuaddr) {
-                       pci_free_consistent (card->pdev, PAGE_SIZE,
-                                            chan->pgtbl[i].cpuaddr,
-                                            chan->pgtbl[i].handle);
-                       chan->pgtbl[i].cpuaddr = NULL;
-                       chan->pgtbl[i].handle = 0;
-               }
-
-       chan->page_number = 0;
-
-       if (chan->sgtable) {
-               pci_free_consistent (card->pdev,
-                       (sizeof (struct via_sgd_table) * chan->frag_number),
-                       (void*)chan->sgtable, chan->sgt_handle);
-               chan->sgtable = NULL;
-       }
-
-       DPRINTK ("EXIT\n");
-}
-
-
-/**
- *     via_chan_pcm_fmt - Update PCM channel settings
- *     @chan: Channel to be updated
- *     @reset: Boolean.  If non-zero, channel will be reset
- *             to 8-bit mono mode.
- *
- *     Stores the settings of the current PCM format,
- *     8-bit or 16-bit, and mono/stereo, into the
- *     hardware settings for the specified channel.
- *     If @reset is non-zero, the channel is reset
- *     to 8-bit mono mode.  Otherwise, the channel
- *     is set to the values stored in the channel
- *     information struct @chan.
- */
-
-static void via_chan_pcm_fmt (struct via_channel *chan, int reset)
-{
-       DPRINTK ("ENTER, pcm_fmt=0x%02X, reset=%s\n",
-                chan->pcm_fmt, reset ? "yes" : "no");
-
-       assert (chan != NULL);
-
-       if (reset)
-       {
-               /* reset to 8-bit mono mode */
-               chan->pcm_fmt = 0;
-               chan->channels = 1;
-       }
-
-       /* enable interrupts on FLAG and EOL */
-       chan->pcm_fmt |= VIA_CHAN_TYPE_MASK;
-
-       /* if we are recording, enable recording fifo bit */
-       if (chan->is_record)
-               chan->pcm_fmt |= VIA_PCM_REC_FIFO;
-       /* set interrupt select bits where applicable (PCM in & out channels) */
-       if (!chan->is_record)
-               chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
-       
-       DPRINTK("SET FMT - %02x %02x\n", chan->intmask , chan->is_multi);
-       
-       if(chan->intmask)
-       {
-               u32 m;
-
-               /*
-                *      Channel 0x4 is up to 6 x 16bit and has to be
-                *      programmed differently 
-                */
-                               
-               if(chan->is_multi)
-               {
-                       u8 c = 0;
-                       
-                       /*
-                        *      Load the type bit for num channels
-                        *      and 8/16bit
-                        */
-                        
-                       if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
-                               c = 1 << 7;
-                       if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
-                               c |= (2<<4);
-                       else
-                               c |= (1<<4);
-                               
-                       outb(c, chan->iobase + VIA_PCM_TYPE);
-                       
-                       /*
-                        *      Set the channel steering
-                        *      Mono
-                        *              Channel 0 to slot 3
-                        *              Channel 0 to slot 4
-                        *      Stereo
-                        *              Channel 0 to slot 3
-                        *              Channel 1 to slot 4
-                        */
-                        
-                       switch(chan->channels)
-                       {
-                               case 1:
-                                       outl(0xFF000000 | (1<<0) | (1<<4) , chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                               case 2:
-                                       outl(0xFF000000 | (1<<0) | (2<<4) , chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                               case 4:
-                                       outl(0xFF000000 | (1<<0) | (2<<4) | (3<<8) | (4<<12), chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                               case 6:
-                                       outl(0xFF000000 | (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20), chan->iobase + VIA_PCM_STOPRATE);
-                                       break;
-                       }                               
-               }
-               else
-               {
-                       /*
-                        *      New style, turn off channel volume
-                        *      control, set bits in the right register
-                        */     
-                       outb(0x0, chan->iobase + VIA_PCM_LEFTVOL);
-                       outb(0x0, chan->iobase + VIA_PCM_RIGHTVOL);
-
-                       m = inl(chan->iobase + VIA_PCM_STOPRATE);
-                       m &= ~(3<<20);
-                       if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
-                               m |= (1 << 20);
-                       if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
-                               m |= (1 << 21);
-                       outl(m, chan->iobase + VIA_PCM_STOPRATE);
-               }               
-       }
-       else
-               outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
-
-
-       DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
-                chan->pcm_fmt,
-                inb (chan->iobase + VIA_PCM_TYPE));
-}
-
-
-/**
- *     via_chan_clear - Stop DMA channel operation, and reset pointers
- *     @card: the chip to accessed
- *     @chan: Channel to be cleared
- *
- *     Call via_chan_stop to halt DMA operations, and then resets
- *     all software pointers which track DMA operation.
- */
-
-static void via_chan_clear (struct via_info *card, struct via_channel *chan)
-{
-       DPRINTK ("ENTER\n");
-       via_chan_stop (chan->iobase);
-       via_chan_buffer_free(card, chan);
-       chan->is_active = 0;
-       chan->is_mapped = 0;
-       chan->is_enabled = 1;
-       chan->slop_len = 0;
-       chan->sw_ptr = 0;
-       chan->n_irqs = 0;
-       atomic_set (&chan->hw_ptr, 0);
-       DPRINTK ("EXIT\n");
-}
-
-
-/**
- *     via_chan_set_speed - Set PCM sample rate for given channel
- *     @card: Private info for specified board
- *     @chan: Channel whose sample rate will be adjusted
- *     @val: New sample rate, in Khz
- *
- *     Helper function for the %SNDCTL_DSP_SPEED ioctl.  OSS semantics
- *     demand that all audio operations halt (if they are not already
- *     halted) when the %SNDCTL_DSP_SPEED is given.
- *
- *     This function halts all audio operations for the given channel
- *     @chan, and then calls via_set_rate to set the audio hardware
- *     to the new rate.
- */
-
-static int via_chan_set_speed (struct via_info *card,
-                              struct via_channel *chan, int val)
-{
-       DPRINTK ("ENTER, requested rate = %d\n", val);
-
-       via_chan_clear (card, chan);
-
-       val = via_set_rate (card->ac97, chan, val);
-
-       DPRINTK ("EXIT, returning %d\n", val);
-       return val;
-}
-
-
-/**
- *     via_chan_set_fmt - Set PCM sample size for given channel
- *     @card: Private info for specified board
- *     @chan: Channel whose sample size will be adjusted
- *     @val: New sample size, use the %AFMT_xxx constants
- *
- *     Helper function for the %SNDCTL_DSP_SETFMT ioctl.  OSS semantics
- *     demand that all audio operations halt (if they are not already
- *     halted) when the %SNDCTL_DSP_SETFMT is given.
- *
- *     This function halts all audio operations for the given channel
- *     @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- *     to the new sample size, either 8-bit or 16-bit.
- */
-
-static int via_chan_set_fmt (struct via_info *card,
-                            struct via_channel *chan, int val)
-{
-       DPRINTK ("ENTER, val=%s\n",
-                val == AFMT_U8 ? "AFMT_U8" :
-                val == AFMT_S16_LE ? "AFMT_S16_LE" :
-                "unknown");
-
-       via_chan_clear (card, chan);
-
-       assert (val != AFMT_QUERY); /* this case is handled elsewhere */
-
-       switch (val) {
-       case AFMT_S16_LE:
-               if ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) == 0) {
-                       chan->pcm_fmt |= VIA_PCM_FMT_16BIT;
-                       via_chan_pcm_fmt (chan, 0);
-               }
-               break;
-
-       case AFMT_U8:
-               if (chan->pcm_fmt & VIA_PCM_FMT_16BIT) {
-                       chan->pcm_fmt &= ~VIA_PCM_FMT_16BIT;
-                       via_chan_pcm_fmt (chan, 0);
-               }
-               break;
-
-       default:
-               DPRINTK ("unknown AFMT: 0x%X\n", val);
-               val = AFMT_S16_LE;
-       }
-
-       DPRINTK ("EXIT\n");
-       return val;
-}
-
-
-/**
- *     via_chan_set_stereo - Enable or disable stereo for a DMA channel
- *     @card: Private info for specified board
- *     @chan: Channel whose stereo setting will be adjusted
- *     @val: New sample size, use the %AFMT_xxx constants
- *
- *     Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls.  OSS semantics
- *     demand that all audio operations halt (if they are not already
- *     halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given.
- *
- *     This function halts all audio operations for the given channel
- *     @chan, and then calls via_chan_pcm_fmt to set the audio hardware
- *     to enable or disable stereo.
- */
-
-static int via_chan_set_stereo (struct via_info *card,
-                               struct via_channel *chan, int val)
-{
-       DPRINTK ("ENTER, channels = %d\n", val);
-
-       via_chan_clear (card, chan);
-
-       switch (val) {
-
-       /* mono */
-       case 1:
-               chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO;
-               chan->channels = 1;
-               via_chan_pcm_fmt (chan, 0);
-               break;
-
-       /* stereo */
-       case 2:
-               chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
-               chan->channels = 2;
-               via_chan_pcm_fmt (chan, 0);
-               break;
-
-       case 4:
-       case 6:
-               if(chan->is_multi)
-               {
-                       chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
-                       chan->channels = val;
-                       break;
-               }
-       /* unknown */
-       default:
-               val = -EINVAL;
-               break;
-       }
-
-       DPRINTK ("EXIT, returning %d\n", val);
-       return val;
-}
-
-static int via_chan_set_buffering (struct via_info *card,
-                                struct via_channel *chan, int val)
-{
-       int shift;
-
-        DPRINTK ("ENTER\n");
-
-       /* in both cases the buffer cannot be changed */
-       if (chan->is_active || chan->is_mapped) {
-               DPRINTK ("EXIT\n");
-               return -EINVAL;
-       }
-
-       /* called outside SETFRAGMENT */
-       /* set defaults or do nothing */
-       if (val < 0) {
-
-               if (chan->frag_size && chan->frag_number)
-                       goto out;
-
-               DPRINTK ("\n");
-
-               chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate * chan->channels
-                                  * ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
-
-               shift = 0;
-               while (chan->frag_size) {
-                       chan->frag_size >>= 1;
-                       shift++;
-               }
-               chan->frag_size = 1 << shift;
-
-               chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME);
-
-               DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number);
-       } else {
-               chan->frag_size = 1 << (val & 0xFFFF);
-               chan->frag_number = (val >> 16) & 0xFFFF;
-
-               DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number);
-       }
-
-       /* quake3 wants frag_number to be a power of two */
-       shift = 0;
-       while (chan->frag_number) {
-               chan->frag_number >>= 1;
-               shift++;
-       }
-       chan->frag_number = 1 << shift;
-
-       if (chan->frag_size > VIA_MAX_FRAG_SIZE)
-               chan->frag_size = VIA_MAX_FRAG_SIZE;
-       else if (chan->frag_size < VIA_MIN_FRAG_SIZE)
-               chan->frag_size = VIA_MIN_FRAG_SIZE;
-
-       if (chan->frag_number < VIA_MIN_FRAG_NUMBER)
-                chan->frag_number = VIA_MIN_FRAG_NUMBER;
-        if (chan->frag_number > VIA_MAX_FRAG_NUMBER)
-               chan->frag_number = VIA_MAX_FRAG_NUMBER;
-
-       if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES)
-               chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size;
-
-out:
-       if (chan->is_record)
-               atomic_set (&chan->n_frags, 0);
-       else
-               atomic_set (&chan->n_frags, chan->frag_number);
-
-       DPRINTK ("EXIT\n");
-
-       return 0;
-}
-
-#ifdef VIA_CHAN_DUMP_BUFS
-/**
- *     via_chan_dump_bufs - Display DMA table contents
- *     @chan: Channel whose DMA table will be displayed
- *
- *     Debugging function which displays the contents of the
- *     scatter-gather DMA table for the given channel @chan.
- */
-
-static void via_chan_dump_bufs (struct via_channel *chan)
-{
-       int i;
-
-       for (i = 0; i < chan->frag_number; i++) {
-               DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
-                        i, chan->sgtable[i].addr,
-                        chan->sgtable[i].count & 0x00FFFFFF,
-                        chan->sgtable[i].count & VIA_FLAG ? 1 : 0,
-                        chan->sgtable[i].count & VIA_EOL ? 1 : 0);
-       }
-       DPRINTK ("buf_in_use = %d, nextbuf = %d\n",
-                atomic_read (&chan->buf_in_use),
-                atomic_read (&chan->sw_ptr));
-}
-#endif /* VIA_CHAN_DUMP_BUFS */
-
-
-/**
- *     via_chan_flush_frag - Flush partially-full playback buffer to hardware
- *     @chan: Channel whose DMA table will be flushed
- *
- *     Flushes partially-full playback buffer to hardware.
- */
-
-static void via_chan_flush_frag (struct via_channel *chan)
-{
-       DPRINTK ("ENTER\n");
-
-       assert (chan->slop_len > 0);
-
-       if (chan->sw_ptr == (chan->frag_number - 1))
-               chan->sw_ptr = 0;
-       else
-               chan->sw_ptr++;
-
-       chan->slop_len = 0;
-
-       assert (atomic_read (&chan->n_frags) > 0);
-       atomic_dec (&chan->n_frags);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-
-/**
- *     via_chan_maybe_start - Initiate audio hardware DMA operation
- *     @chan: Channel whose DMA is to be started
- *
- *     Initiate DMA operation, if the DMA engine for the given
- *     channel @chan is not already active.
- */
-
-static inline void via_chan_maybe_start (struct via_channel *chan)
-{
-       assert (chan->is_active == sg_active(chan->iobase));
-
-       DPRINTK ("MAYBE START %s\n", chan->name);
-       if (!chan->is_active && chan->is_enabled) {
-               chan->is_active = 1;
-               sg_begin (chan);
-               DPRINTK ("starting channel %s\n", chan->name);
-       }
-}
-
-
-/****************************************************************
- *
- * Interface to ac97-codec module
- *
- *
- */
-
-/**
- *     via_ac97_wait_idle - Wait until AC97 codec is not busy
- *     @card: Private info for specified board
- *
- *     Sleep until the AC97 codec is no longer busy.
- *     Returns the final value read from the SGD
- *     register being polled.
- */
-
-static u8 via_ac97_wait_idle (struct via_info *card)
-{
-       u8 tmp8;
-       int counter = VIA_COUNTER_LIMIT;
-
-       DPRINTK ("ENTER/EXIT\n");
-
-       assert (card != NULL);
-       assert (card->pdev != NULL);
-
-       do {
-               udelay (15);
-
-               tmp8 = inb (card->baseaddr + 0x83);
-       } while ((tmp8 & VIA_CR83_BUSY) && (counter-- > 0));
-
-       if (tmp8 & VIA_CR83_BUSY)
-               printk (KERN_WARNING PFX "timeout waiting on AC97 codec\n");
-       return tmp8;
-}
-
-
-/**
- *     via_ac97_read_reg - Read AC97 standard register
- *     @codec: Pointer to generic AC97 codec info
- *     @reg: Index of AC97 register to be read
- *
- *     Read the value of a single AC97 codec register,
- *     as defined by the Intel AC97 specification.
- *
- *     Defines the standard AC97 read-register operation
- *     required by the kernel's ac97_codec interface.
- *
- *     Returns the 16-bit value stored in the specified
- *     register.
- */
-
-static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg)
-{
-       unsigned long data;
-       struct via_info *card;
-       int counter;
-
-       DPRINTK ("ENTER\n");
-
-       assert (codec != NULL);
-       assert (codec->private_data != NULL);
-
-       card = codec->private_data;
-       
-       spin_lock(&card->ac97_lock);
-
-       /* Every time we write to register 80 we cause a transaction.
-          The only safe way to clear the valid bit is to write it at
-          the same time as the command */
-       data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID;
-
-       outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
-       udelay (20);
-
-       for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
-               udelay (1);
-               if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) &
-                     (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID))
-                       goto out;
-       }
-
-       printk (KERN_WARNING PFX "timeout while reading AC97 codec (0x%lX)\n", data);
-       goto err_out;
-
-out:
-       /* Once the valid bit has become set, we must wait a complete AC97
-          frame before the data has settled. */
-       udelay(25);
-       data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL);
-
-       outb (0x02, card->baseaddr + 0x83);
-
-       if (((data & 0x007F0000) >> 16) == reg) {
-               DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n",
-                        data, data & 0x0000FFFF);
-               spin_unlock(&card->ac97_lock);
-               return data & 0x0000FFFF;
-       }
-
-       printk (KERN_WARNING "via82cxxx_audio: not our index: reg=0x%x, newreg=0x%lx\n",
-               reg, ((data & 0x007F0000) >> 16));
-
-err_out:
-       spin_unlock(&card->ac97_lock);
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-/**
- *     via_ac97_write_reg - Write AC97 standard register
- *     @codec: Pointer to generic AC97 codec info
- *     @reg: Index of AC97 register to be written
- *     @value: Value to be written to AC97 register
- *
- *     Write the value of a single AC97 codec register,
- *     as defined by the Intel AC97 specification.
- *
- *     Defines the standard AC97 write-register operation
- *     required by the kernel's ac97_codec interface.
- */
-
-static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value)
-{
-       u32 data;
-       struct via_info *card;
-       int counter;
-
-       DPRINTK ("ENTER\n");
-
-       assert (codec != NULL);
-       assert (codec->private_data != NULL);
-
-       card = codec->private_data;
-
-       spin_lock(&card->ac97_lock);
-       
-       data = (reg << 16) + value;
-       outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);
-       udelay (10);
-
-       for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {
-               if ((inb (card->baseaddr + 0x83) & VIA_CR83_BUSY) == 0)
-                       goto out;
-
-               udelay (15);
-       }
-
-       printk (KERN_WARNING PFX "timeout after AC97 codec write (0x%X, 0x%X)\n", reg, value);
-
-out:
-       spin_unlock(&card->ac97_lock);
-       DPRINTK ("EXIT\n");
-}
-
-
-static int via_mixer_open (struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct via_info *card;
-       struct pci_dev *pdev = NULL;
-       struct pci_driver *drvr;
-
-       DPRINTK ("ENTER\n");
-
-       while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-               drvr = pci_dev_driver (pdev);
-               if (drvr == &via_driver) {
-                       assert (pci_get_drvdata (pdev) != NULL);
-
-                       card = pci_get_drvdata (pdev);
-                       if (card->ac97->dev_mixer == minor)
-                               goto match;
-               }
-       }
-
-       DPRINTK ("EXIT, returning -ENODEV\n");
-       return -ENODEV;
-
-match:
-       pci_dev_put(pdev);
-       file->private_data = card->ac97;
-
-       DPRINTK ("EXIT, returning 0\n");
-       return nonseekable_open(inode, file);
-}
-
-static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-                           unsigned long arg)
-{
-       struct ac97_codec *codec = file->private_data;
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc;
-
-       DPRINTK ("ENTER\n");
-
-       assert (codec != NULL);
-       card = codec->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-       
-#if 0
-       /*
-        *      Intercept volume control on 8233 and 8235
-        */
-       if(card->volume)
-       {
-               switch(cmd)
-               {
-                       case SOUND_MIXER_READ_VOLUME:
-                               return card->mixer_vol;
-                       case SOUND_MIXER_WRITE_VOLUME:
-                       {
-                               int v;
-                               if(get_user(v, (int *)arg))
-                               {
-                                       rc = -EFAULT;
-                                       goto out;
-                               }
-                               card->mixer_vol = v;
-                       }
-               }
-       }               
-#endif
-       rc = codec->mixer_ioctl(codec, cmd, arg);
-
-       mutex_unlock(&card->syscall_mutex);
-
-out:
-       DPRINTK ("EXIT, returning %d\n", rc);
-       return rc;
-}
-
-
-static const struct file_operations via_mixer_fops = {
-       .owner          = THIS_MODULE,
-       .open           = via_mixer_open,
-       .llseek         = no_llseek,
-       .ioctl          = via_mixer_ioctl,
-};
-
-
-static int __devinit via_ac97_reset (struct via_info *card)
-{
-       struct pci_dev *pdev = card->pdev;
-       u8 tmp8;
-       u16 tmp16;
-
-       DPRINTK ("ENTER\n");
-
-       assert (pdev != NULL);
-
-#ifndef NDEBUG
-       {
-               u8 r40,r41,r42,r43,r44,r48;
-               pci_read_config_byte (card->pdev, 0x40, &r40);
-               pci_read_config_byte (card->pdev, 0x41, &r41);
-               pci_read_config_byte (card->pdev, 0x42, &r42);
-               pci_read_config_byte (card->pdev, 0x43, &r43);
-               pci_read_config_byte (card->pdev, 0x44, &r44);
-               pci_read_config_byte (card->pdev, 0x48, &r48);
-               DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
-                       r40,r41,r42,r43,r44,r48);
-
-               spin_lock_irq (&card->lock);
-               DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                        inb (card->baseaddr + 0x00),
-                        inb (card->baseaddr + 0x01),
-                        inb (card->baseaddr + 0x02),
-                        inl (card->baseaddr + 0x04),
-                        inl (card->baseaddr + 0x0C),
-                        inl (card->baseaddr + 0x80),
-                        inl (card->baseaddr + 0x84));
-               spin_unlock_irq (&card->lock);
-
-       }
-#endif
-
-        /*
-         * Reset AC97 controller: enable, disable, enable,
-         * pausing after each command for good luck.  Only
-        * do this if the codec is not ready, because it causes
-        * loud pops and such due to such a hard codec reset.
-         */
-       pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8);
-       if ((tmp8 & VIA_CR40_AC97_READY) == 0) {
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
-                                      VIA_CR41_AC97_ENABLE |
-                                      VIA_CR41_AC97_RESET |
-                                      VIA_CR41_AC97_WAKEUP);
-               udelay (100);
-
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);
-               udelay (100);
-
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
-                                      VIA_CR41_AC97_ENABLE |
-                                      VIA_CR41_PCM_ENABLE |
-                                      VIA_CR41_VRA | VIA_CR41_AC97_RESET);
-               udelay (100);
-       }
-
-       /* Make sure VRA is enabled, in case we didn't do a
-        * complete codec reset, above
-        */
-       pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);
-       if (((tmp8 & VIA_CR41_VRA) == 0) ||
-           ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) ||
-           ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) ||
-           ((tmp8 & VIA_CR41_AC97_RESET) == 0)) {
-               pci_write_config_byte (pdev, VIA_ACLINK_CTRL,
-                                      VIA_CR41_AC97_ENABLE |
-                                      VIA_CR41_PCM_ENABLE |
-                                      VIA_CR41_VRA | VIA_CR41_AC97_RESET);
-               udelay (100);
-       }
-
-       if(card->legacy)
-       {
-#if 0 /* this breaks on K7M */
-               /* disable legacy stuff */
-               pci_write_config_byte (pdev, 0x42, 0x00);
-               udelay(10);
-#endif
-
-               /* route FM trap to IRQ, disable FM trap */
-               pci_write_config_byte (pdev, 0x48, 0x05);
-               udelay(10);
-       }
-       
-       /* disable all codec GPI interrupts */
-       outl (0, pci_resource_start (pdev, 0) + 0x8C);
-
-       /* WARNING: this line is magic.  Remove this
-        * and things break. */
-       /* enable variable rate */
-       tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-       if ((tmp16 & 1) == 0)
-               via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-static void via_ac97_codec_wait (struct ac97_codec *codec)
-{
-       assert (codec->private_data != NULL);
-       via_ac97_wait_idle (codec->private_data);
-}
-
-
-static int __devinit via_ac97_init (struct via_info *card)
-{
-       int rc;
-       u16 tmp16;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-
-       card->ac97 = ac97_alloc_codec();
-       if(card->ac97 == NULL)
-               return -ENOMEM;
-               
-       card->ac97->private_data = card;
-       card->ac97->codec_read = via_ac97_read_reg;
-       card->ac97->codec_write = via_ac97_write_reg;
-       card->ac97->codec_wait = via_ac97_codec_wait;
-
-       card->ac97->dev_mixer = register_sound_mixer (&via_mixer_fops, -1);
-       if (card->ac97->dev_mixer < 0) {
-               printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");
-               DPRINTK ("EXIT, returning -EIO\n");
-               ac97_release_codec(card->ac97);
-               return -EIO;
-       }
-
-       rc = via_ac97_reset (card);
-       if (rc) {
-               printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n");
-               goto err_out;
-       }
-       
-       mdelay(10);
-       
-       if (ac97_probe_codec (card->ac97) == 0) {
-               printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n");
-               rc = -EIO;
-               goto err_out;
-       }
-
-       /* enable variable rate */
-       tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-       via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-
-       /*
-        * If we cannot enable VRA, we have a locked-rate codec.
-        * We try again to enable VRA before assuming so, however.
-        */
-       tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-       if ((tmp16 & 1) == 0) {
-               via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
-               tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS);
-               if ((tmp16 & 1) == 0) {
-                       card->locked_rate = 1;
-                       printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
-               }
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-
-err_out:
-       unregister_sound_mixer (card->ac97->dev_mixer);
-       DPRINTK ("EXIT, returning %d\n", rc);
-       ac97_release_codec(card->ac97);
-       return rc;
-}
-
-
-static void via_ac97_cleanup (struct via_info *card)
-{
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-       assert (card->ac97->dev_mixer >= 0);
-
-       unregister_sound_mixer (card->ac97->dev_mixer);
-       ac97_release_codec(card->ac97);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-
-/****************************************************************
- *
- * Interrupt-related code
- *
- */
-
-/**
- *     via_intr_channel - handle an interrupt for a single channel
- *      @card: unused
- *     @chan: handle interrupt for this channel
- *
- *     This is the "meat" of the interrupt handler,
- *     containing the actions taken each time an interrupt
- *     occurs.  All communication and coordination with
- *     userspace takes place here.
- *
- *     Locking: inside card->lock
- */
-
-static void via_intr_channel (struct via_info *card, struct via_channel *chan)
-{
-       u8 status;
-       int n;
-       
-       /* check pertinent bits of status register for action bits */
-       status = inb (chan->iobase) & (VIA_SGD_FLAG | VIA_SGD_EOL | VIA_SGD_STOPPED);
-       if (!status)
-               return;
-
-       /* acknowledge any flagged bits ASAP */
-       outb (status, chan->iobase);
-
-       if (!chan->sgtable) /* XXX: temporary solution */
-               return;
-
-       /* grab current h/w ptr value */
-       n = atomic_read (&chan->hw_ptr);
-
-       /* sanity check: make sure our h/w ptr doesn't have a weird value */
-       assert (n >= 0);
-       assert (n < chan->frag_number);
-
-       
-       /* reset SGD data structure in memory to reflect a full buffer,
-        * and advance the h/w ptr, wrapping around to zero if needed
-        */
-       if (n == (chan->frag_number - 1)) {
-               chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_EOL);
-               atomic_set (&chan->hw_ptr, 0);
-       } else {
-               chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_FLAG);
-               atomic_inc (&chan->hw_ptr);
-       }
-
-       /* accounting crap for SNDCTL_DSP_GETxPTR */
-       chan->n_irqs++;
-       chan->bytes += chan->frag_size;
-       /* FIXME - signed overflow is undefined */
-       if (chan->bytes < 0) /* handle overflow of 31-bit value */
-               chan->bytes = chan->frag_size;
-       /* all following checks only occur when not in mmap(2) mode */
-       if (!chan->is_mapped)
-       {
-               /* If we are recording, then n_frags represents the number
-                * of fragments waiting to be handled by userspace.
-                * If we are playback, then n_frags represents the number
-                * of fragments remaining to be filled by userspace.
-                * We increment here.  If we reach max number of fragments,
-                * this indicates an underrun/overrun.  For this case under OSS,
-                * we stop the record/playback process.
-                */
-               if (atomic_read (&chan->n_frags) < chan->frag_number)
-                       atomic_inc (&chan->n_frags);
-               assert (atomic_read (&chan->n_frags) <= chan->frag_number);
-               if (atomic_read (&chan->n_frags) == chan->frag_number) {
-                       chan->is_active = 0;
-                       via_chan_stop (chan->iobase);
-               }
-       }
-       /* wake up anyone listening to see when interrupts occur */
-       wake_up_all (&chan->wait);
-
-       DPRINTK ("%s intr, status=0x%02X, hwptr=0x%lX, chan->hw_ptr=%d\n",
-                chan->name, status, (long) inl (chan->iobase + 0x04),
-                atomic_read (&chan->hw_ptr));
-
-       DPRINTK ("%s intr, channel n_frags == %d, missed %d\n", chan->name,
-                atomic_read (&chan->n_frags), missed);
-}
-
-
-static irqreturn_t  via_interrupt(int irq, void *dev_id)
-{
-       struct via_info *card = dev_id;
-       u32 status32;
-
-       /* to minimize interrupt sharing costs, we use the SGD status
-        * shadow register to check the status of all inputs and
-        * outputs with a single 32-bit bus read.  If no interrupt
-        * conditions are flagged, we exit immediately
-        */
-       status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
-       if (!(status32 & VIA_INTR_MASK))
-        {
-#ifdef CONFIG_MIDI_VIA82CXXX
-                if (card->midi_devc)
-                       uart401intr(irq, card->midi_devc);
-#endif
-               return IRQ_HANDLED;
-       }
-       DPRINTK ("intr, status32 == 0x%08X\n", status32);
-
-       /* synchronize interrupt handling under SMP.  this spinlock
-        * goes away completely on UP
-        */
-       spin_lock (&card->lock);
-
-       if (status32 & VIA_INTR_OUT)
-               via_intr_channel (card, &card->ch_out);
-       if (status32 & VIA_INTR_IN)
-               via_intr_channel (card, &card->ch_in);
-       if (status32 & VIA_INTR_FM)
-               via_intr_channel (card, &card->ch_fm);
-
-       spin_unlock (&card->lock);
-       
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t via_new_interrupt(int irq, void *dev_id)
-{
-       struct via_info *card = dev_id;
-       u32 status32;
-
-       /* to minimize interrupt sharing costs, we use the SGD status
-        * shadow register to check the status of all inputs and
-        * outputs with a single 32-bit bus read.  If no interrupt
-        * conditions are flagged, we exit immediately
-        */
-       status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
-       if (!(status32 & VIA_NEW_INTR_MASK))
-               return IRQ_NONE;
-       /*
-        * goes away completely on UP
-        */
-       spin_lock (&card->lock);
-
-       via_intr_channel (card, &card->ch_out);
-       via_intr_channel (card, &card->ch_in);
-       via_intr_channel (card, &card->ch_fm);
-
-       spin_unlock (&card->lock);
-       return IRQ_HANDLED;
-}
-
-
-/**
- *     via_interrupt_init - Initialize interrupt handling
- *     @card: Private info for specified board
- *
- *     Obtain and reserve IRQ for using in handling audio events.
- *     Also, disable any IRQ-generating resources, to make sure
- *     we don't get interrupts before we want them.
- */
-
-static int via_interrupt_init (struct via_info *card)
-{
-       u8 tmp8;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-       assert (card->pdev != NULL);
-
-       /* check for sane IRQ number. can this ever happen? */
-       if (card->pdev->irq < 2) {
-               printk (KERN_ERR PFX "insane IRQ %d, aborting\n",
-                       card->pdev->irq);
-               DPRINTK ("EXIT, returning -EIO\n");
-               return -EIO;
-       }
-
-       /* VIA requires this is done */
-       pci_write_config_byte(card->pdev, PCI_INTERRUPT_LINE, card->pdev->irq);
-       
-       if(card->legacy)
-       {
-               /* make sure FM irq is not routed to us */
-               pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
-               if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
-                       tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
-                       pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
-               }
-               if (request_irq (card->pdev->irq, via_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
-                       printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
-                               card->pdev->irq);
-                       DPRINTK ("EXIT, returning -EBUSY\n");
-                       return -EBUSY;
-               }
-       }
-       else 
-       {
-               if (request_irq (card->pdev->irq, via_new_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) {
-                       printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
-                               card->pdev->irq);
-                       DPRINTK ("EXIT, returning -EBUSY\n");
-                       return -EBUSY;
-               }
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-/****************************************************************
- *
- * OSS DSP device
- *
- */
-
-static const struct file_operations via_dsp_fops = {
-       .owner          = THIS_MODULE,
-       .open           = via_dsp_open,
-       .release        = via_dsp_release,
-       .read           = via_dsp_read,
-       .write          = via_dsp_write,
-       .poll           = via_dsp_poll,
-       .llseek         = no_llseek,
-       .ioctl          = via_dsp_ioctl,
-       .mmap           = via_dsp_mmap,
-};
-
-
-static int __devinit via_dsp_init (struct via_info *card)
-{
-       u8 tmp8;
-
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-
-       if(card->legacy)
-       {
-               /* turn off legacy features, if not already */
-               pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);
-               if (tmp8 & (VIA_CR42_SB_ENABLE |  VIA_CR42_FM_ENABLE)) {
-                       tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE);
-                       pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);
-               }
-       }
-
-       via_stop_everything (card);
-
-       card->dev_dsp = register_sound_dsp (&via_dsp_fops, -1);
-       if (card->dev_dsp < 0) {
-               DPRINTK ("EXIT, returning -ENODEV\n");
-               return -ENODEV;
-       }
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-static void via_dsp_cleanup (struct via_info *card)
-{
-       DPRINTK ("ENTER\n");
-
-       assert (card != NULL);
-       assert (card->dev_dsp >= 0);
-
-       via_stop_everything (card);
-
-       unregister_sound_dsp (card->dev_dsp);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-static struct page * via_mm_nopage (struct vm_area_struct * vma,
-                                   unsigned long address, int *type)
-{
-       struct via_info *card = vma->vm_private_data;
-       struct via_channel *chan = &card->ch_out;
-       unsigned long max_bufs;
-       struct page *dmapage;
-       unsigned long pgoff;
-       int rd, wr;
-
-       DPRINTK ("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n",
-                vma->vm_start,
-                address - vma->vm_start,
-                (address - vma->vm_start) >> PAGE_SHIFT,
-                address);
-
-        if (address > vma->vm_end) {
-               DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
-               return NOPAGE_SIGBUS; /* Disallow mremap */
-       }
-        if (!card) {
-               DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
-               return NOPAGE_SIGBUS;   /* Nothing allocated */
-       }
-
-       pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT);
-       rd = card->ch_in.is_mapped;
-       wr = card->ch_out.is_mapped;
-
-       max_bufs = chan->frag_number;
-       if (rd && wr)
-               max_bufs *= 2;
-       if (pgoff >= max_bufs)
-               return NOPAGE_SIGBUS;
-
-       /* if full-duplex (read+write) and we have two sets of bufs,
-        * then the playback buffers come first, sez soundcard.c */
-       if (pgoff >= chan->page_number) {
-               pgoff -= chan->page_number;
-               chan = &card->ch_in;
-       } else if (!wr)
-               chan = &card->ch_in;
-
-       assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0);
-
-       dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr);
-       DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",
-                dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr);
-       get_page (dmapage);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return dmapage;
-}
-
-
-#ifndef VM_RESERVED
-static int via_mm_swapout (struct page *page, struct file *filp)
-{
-       return 0;
-}
-#endif /* VM_RESERVED */
-
-
-static struct vm_operations_struct via_mm_ops = {
-       .nopage         = via_mm_nopage,
-
-#ifndef VM_RESERVED
-       .swapout        = via_mm_swapout,
-#endif
-};
-
-
-static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc = -EINVAL, rd=0, wr=0;
-       unsigned long max_size, size, start, offset;
-
-       assert (file != NULL);
-       assert (vma != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       DPRINTK ("ENTER, start %lXh, size %ld, pgoff %ld\n",
-                vma->vm_start,
-                vma->vm_end - vma->vm_start,
-                vma->vm_pgoff);
-
-       max_size = 0;
-       if (vma->vm_flags & VM_READ) {
-               rd = 1;
-               via_chan_set_buffering(card, &card->ch_in, -1);
-               via_chan_buffer_init (card, &card->ch_in);
-               max_size += card->ch_in.page_number << PAGE_SHIFT;
-       }
-       if (vma->vm_flags & VM_WRITE) {
-               wr = 1;
-               via_chan_set_buffering(card, &card->ch_out, -1);
-               via_chan_buffer_init (card, &card->ch_out);
-               max_size += card->ch_out.page_number << PAGE_SHIFT;
-       }
-
-       start = vma->vm_start;
-       offset = (vma->vm_pgoff << PAGE_SHIFT);
-       size = vma->vm_end - vma->vm_start;
-
-       /* some basic size/offset sanity checks */
-       if (size > max_size)
-               goto out;
-       if (offset > max_size - size)
-               goto out;
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-
-       vma->vm_ops = &via_mm_ops;
-       vma->vm_private_data = card;
-
-#ifdef VM_RESERVED
-       vma->vm_flags |= VM_RESERVED;
-#endif
-
-       if (rd)
-               card->ch_in.is_mapped = 1;
-       if (wr)
-               card->ch_out.is_mapped = 1;
-
-       mutex_unlock(&card->syscall_mutex);
-       rc = 0;
-
-out:
-       DPRINTK ("EXIT, returning %d\n", rc);
-       return rc;
-}
-
-
-static ssize_t via_dsp_do_read (struct via_info *card,
-                               char __user *userbuf, size_t count,
-                               int nonblock)
-{
-        DECLARE_WAITQUEUE(wait, current);
-       const char __user *orig_userbuf = userbuf;
-       struct via_channel *chan = &card->ch_in;
-       size_t size;
-       int n, tmp;
-       ssize_t ret = 0;
-
-       /* if SGD has not yet been started, start it */
-       via_chan_maybe_start (chan);
-
-handle_one_block:
-       /* just to be a nice neighbor */
-       /* Thomas Sailer:
-        * But also to ourselves, release semaphore if we do so */
-       if (need_resched()) {
-               mutex_unlock(&card->syscall_mutex);
-               schedule ();
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       goto out;
-       }
-
-       /* grab current channel software pointer.  In the case of
-        * recording, this is pointing to the next buffer that
-        * will receive data from the audio hardware.
-        */
-       n = chan->sw_ptr;
-
-       /* n_frags represents the number of fragments waiting
-        * to be copied to userland.  sleep until at least
-        * one buffer has been read from the audio hardware.
-        */
-       add_wait_queue(&chan->wait, &wait);
-       for (;;) {
-               __set_current_state(TASK_INTERRUPTIBLE);
-               tmp = atomic_read (&chan->n_frags);
-               assert (tmp >= 0);
-               assert (tmp <= chan->frag_number);
-               if (tmp)
-                       break;
-               if (nonblock || !chan->is_active) {
-                       ret = -EAGAIN;
-                       break;
-               }
-
-               mutex_unlock(&card->syscall_mutex);
-
-               DPRINTK ("Sleeping on block %d\n", n);
-               schedule();
-
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       break;
-
-               if (signal_pending (current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&chan->wait, &wait);
-       if (ret)
-               goto out;
-
-       /* Now that we have a buffer we can read from, send
-        * as much as sample data possible to userspace.
-        */
-       while ((count > 0) && (chan->slop_len < chan->frag_size)) {
-               size_t slop_left = chan->frag_size - chan->slop_len;
-               void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr;
-               unsigned ofs = (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
-
-               size = (count < slop_left) ? count : slop_left;
-               if (copy_to_user (userbuf,
-                                 base + ofs + chan->slop_len,
-                                 size)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-
-               count -= size;
-               chan->slop_len += size;
-               userbuf += size;
-       }
-
-       /* If we didn't copy the buffer completely to userspace,
-        * stop now.
-        */
-       if (chan->slop_len < chan->frag_size)
-               goto out;
-
-       /*
-        * If we get to this point, we copied one buffer completely
-        * to userspace, give the buffer back to the hardware.
-        */
-
-       /* advance channel software pointer to point to
-        * the next buffer from which we will copy
-        */
-       if (chan->sw_ptr == (chan->frag_number - 1))
-               chan->sw_ptr = 0;
-       else
-               chan->sw_ptr++;
-
-       /* mark one less buffer waiting to be processed */
-       assert (atomic_read (&chan->n_frags) > 0);
-       atomic_dec (&chan->n_frags);
-
-       /* we are at a block boundary, there is no fragment data */
-       chan->slop_len = 0;
-
-       DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
-               n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
-       DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                inb (card->baseaddr + 0x00),
-                inb (card->baseaddr + 0x01),
-                inb (card->baseaddr + 0x02),
-                inl (card->baseaddr + 0x04),
-                inl (card->baseaddr + 0x0C),
-                inl (card->baseaddr + 0x80),
-                inl (card->baseaddr + 0x84));
-
-       if (count > 0)
-               goto handle_one_block;
-
-out:
-       return (userbuf != orig_userbuf) ? (userbuf - orig_userbuf) : ret;
-}
-
-
-static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc;
-
-       DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
-                file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-
-       if (card->ch_in.is_mapped) {
-               rc = -ENXIO;
-               goto out_up;
-       }
-
-       via_chan_set_buffering(card, &card->ch_in, -1);
-        rc = via_chan_buffer_init (card, &card->ch_in);
-
-       if (rc)
-               goto out_up;
-
-       rc = via_dsp_do_read (card, buffer, count, nonblock);
-
-out_up:
-       mutex_unlock(&card->syscall_mutex);
-out:
-       DPRINTK ("EXIT, returning %ld\n",(long) rc);
-       return rc;
-}
-
-
-static ssize_t via_dsp_do_write (struct via_info *card,
-                                const char __user *userbuf, size_t count,
-                                int nonblock)
-{
-        DECLARE_WAITQUEUE(wait, current);
-       const char __user *orig_userbuf = userbuf;
-       struct via_channel *chan = &card->ch_out;
-       volatile struct via_sgd_table *sgtable = chan->sgtable;
-       size_t size;
-       int n, tmp;
-       ssize_t ret = 0;
-
-handle_one_block:
-       /* just to be a nice neighbor */
-       /* Thomas Sailer:
-        * But also to ourselves, release semaphore if we do so */
-       if (need_resched()) {
-               mutex_unlock(&card->syscall_mutex);
-               schedule ();
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       goto out;
-       }
-
-       /* grab current channel fragment pointer.  In the case of
-        * playback, this is pointing to the next fragment that
-        * should receive data from userland.
-        */
-       n = chan->sw_ptr;
-
-       /* n_frags represents the number of fragments remaining
-        * to be filled by userspace.  Sleep until
-        * at least one fragment is available for our use.
-        */
-       add_wait_queue(&chan->wait, &wait);
-       for (;;) {
-               __set_current_state(TASK_INTERRUPTIBLE);
-               tmp = atomic_read (&chan->n_frags);
-               assert (tmp >= 0);
-               assert (tmp <= chan->frag_number);
-               if (tmp)
-                       break;
-               if (nonblock || !chan->is_active) {
-                       ret = -EAGAIN;
-                       break;
-               }
-
-               mutex_unlock(&card->syscall_mutex);
-
-               DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
-               schedule();
-
-               ret = via_syscall_down (card, nonblock);
-               if (ret)
-                       break;
-
-               if (signal_pending (current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&chan->wait, &wait);
-       if (ret)
-               goto out;
-
-       /* Now that we have at least one fragment we can write to, fill the buffer
-        * as much as possible with data from userspace.
-        */
-       while ((count > 0) && (chan->slop_len < chan->frag_size)) {
-               size_t slop_left = chan->frag_size - chan->slop_len;
-
-               size = (count < slop_left) ? count : slop_left;
-               if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len,
-                                   userbuf, size)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-
-               count -= size;
-               chan->slop_len += size;
-               userbuf += size;
-       }
-
-       /* If we didn't fill up the buffer with data, stop now.
-         * Put a 'stop' marker in the DMA table too, to tell the
-         * audio hardware to stop if it gets here.
-         */
-       if (chan->slop_len < chan->frag_size) {
-               sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP);
-               goto out;
-       }
-
-       /*
-         * If we get to this point, we have filled a buffer with
-         * audio data, flush the buffer to audio hardware.
-         */
-
-       /* Record the true size for the audio hardware to notice */
-        if (n == (chan->frag_number - 1))
-                sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
-        else
-                sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
-
-       /* advance channel software pointer to point to
-        * the next buffer we will fill with data
-        */
-       if (chan->sw_ptr == (chan->frag_number - 1))
-               chan->sw_ptr = 0;
-       else
-               chan->sw_ptr++;
-
-       /* mark one less buffer as being available for userspace consumption */
-       assert (atomic_read (&chan->n_frags) > 0);
-       atomic_dec (&chan->n_frags);
-
-       /* we are at a block boundary, there is no fragment data */
-       chan->slop_len = 0;
-
-       /* if SGD has not yet been started, start it */
-       via_chan_maybe_start (chan);
-
-       DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
-               n, chan->sw_ptr, atomic_read (&chan->n_frags));
-
-       DPRINTK ("regs==S=%02X C=%02X TP=%02X BP=%08X RT=%08X SG=%08X CC=%08X SS=%08X\n",
-                inb (card->baseaddr + 0x00),
-                inb (card->baseaddr + 0x01),
-                inb (card->baseaddr + 0x02),
-                inl (card->baseaddr + 0x04),
-                inl (card->baseaddr + 0x08),
-                inl (card->baseaddr + 0x0C),
-                inl (card->baseaddr + 0x80),
-                inl (card->baseaddr + 0x84));
-
-       if (count > 0)
-               goto handle_one_block;
-
-out:
-       if (userbuf - orig_userbuf)
-               return userbuf - orig_userbuf;
-       else
-               return ret;
-}
-
-
-static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-       struct via_info *card;
-       ssize_t rc;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-
-       DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",
-                file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) goto out;
-
-       if (card->ch_out.is_mapped) {
-               rc = -ENXIO;
-               goto out_up;
-       }
-
-       via_chan_set_buffering(card, &card->ch_out, -1);
-       rc = via_chan_buffer_init (card, &card->ch_out);
-
-       if (rc)
-               goto out_up;
-
-       rc = via_dsp_do_write (card, buffer, count, nonblock);
-
-out_up:
-       mutex_unlock(&card->syscall_mutex);
-out:
-       DPRINTK ("EXIT, returning %ld\n",(long) rc);
-       return rc;
-}
-
-
-static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct via_info *card;
-       struct via_channel *chan;
-       unsigned int mask = 0;
-
-       DPRINTK ("ENTER\n");
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       if (file->f_mode & FMODE_READ) {
-               chan = &card->ch_in;
-               if (sg_active (chan->iobase))
-                       poll_wait(file, &chan->wait, wait);
-               if (atomic_read (&chan->n_frags) > 0)
-                       mask |= POLLIN | POLLRDNORM;
-       }
-
-       if (file->f_mode & FMODE_WRITE) {
-               chan = &card->ch_out;
-               if (sg_active (chan->iobase))
-                       poll_wait(file, &chan->wait, wait);
-               if (atomic_read (&chan->n_frags) > 0)
-                       mask |= POLLOUT | POLLWRNORM;
-       }
-
-       DPRINTK ("EXIT, returning %u\n", mask);
-       return mask;
-}
-
-
-/**
- *     via_dsp_drain_playback - sleep until all playback samples are flushed
- *     @card: Private info for specified board
- *     @chan: Channel to drain
- *     @nonblock: boolean, non-zero if O_NONBLOCK is set
- *
- *     Sleeps until all playback has been flushed to the audio
- *     hardware.
- *
- *     Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_drain_playback (struct via_info *card,
-                                  struct via_channel *chan, int nonblock)
-{
-        DECLARE_WAITQUEUE(wait, current);
-       int ret = 0;
-
-       DPRINTK ("ENTER, nonblock = %d\n", nonblock);
-
-       if (chan->slop_len > 0)
-               via_chan_flush_frag (chan);
-
-       if (atomic_read (&chan->n_frags) == chan->frag_number)
-               goto out;
-
-       via_chan_maybe_start (chan);
-
-       add_wait_queue(&chan->wait, &wait);
-       for (;;) {
-               DPRINTK ("FRAGS %d FRAGNUM %d\n", atomic_read(&chan->n_frags), chan->frag_number);
-               __set_current_state(TASK_INTERRUPTIBLE);
-               if (atomic_read (&chan->n_frags) >= chan->frag_number)
-                       break;
-
-               if (nonblock) {
-                       DPRINTK ("EXIT, returning -EAGAIN\n");
-                       ret = -EAGAIN;
-                       break;
-               }
-
-#ifdef VIA_DEBUG
-               {
-               u8 r40,r41,r42,r43,r44,r48;
-               pci_read_config_byte (card->pdev, 0x40, &r40);
-               pci_read_config_byte (card->pdev, 0x41, &r41);
-               pci_read_config_byte (card->pdev, 0x42, &r42);
-               pci_read_config_byte (card->pdev, 0x43, &r43);
-               pci_read_config_byte (card->pdev, 0x44, &r44);
-               pci_read_config_byte (card->pdev, 0x48, &r48);
-               DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
-                       r40,r41,r42,r43,r44,r48);
-
-               DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                        inb (card->baseaddr + 0x00),
-                        inb (card->baseaddr + 0x01),
-                        inb (card->baseaddr + 0x02),
-                        inl (card->baseaddr + 0x04),
-                        inl (card->baseaddr + 0x0C),
-                        inl (card->baseaddr + 0x80),
-                        inl (card->baseaddr + 0x84));
-               }
-
-               if (!chan->is_active)
-                       printk (KERN_ERR "sleeping but not active\n");
-#endif
-
-               mutex_unlock(&card->syscall_mutex);
-
-               DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
-               schedule();
-
-               if ((ret = via_syscall_down (card, nonblock)))
-                       break;
-
-               if (signal_pending (current)) {
-                       DPRINTK ("EXIT, returning -ERESTARTSYS\n");
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&chan->wait, &wait);
-
-#ifdef VIA_DEBUG
-       {
-               u8 r40,r41,r42,r43,r44,r48;
-               pci_read_config_byte (card->pdev, 0x40, &r40);
-               pci_read_config_byte (card->pdev, 0x41, &r41);
-               pci_read_config_byte (card->pdev, 0x42, &r42);
-               pci_read_config_byte (card->pdev, 0x43, &r43);
-               pci_read_config_byte (card->pdev, 0x44, &r44);
-               pci_read_config_byte (card->pdev, 0x48, &r48);
-               DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
-                       r40,r41,r42,r43,r44,r48);
-
-               DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
-                        inb (card->baseaddr + 0x00),
-                        inb (card->baseaddr + 0x01),
-                        inb (card->baseaddr + 0x02),
-                        inl (card->baseaddr + 0x04),
-                        inl (card->baseaddr + 0x0C),
-                        inl (card->baseaddr + 0x80),
-                        inl (card->baseaddr + 0x84));
-
-               DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags));
-       }
-#endif
-
-out:
-       DPRINTK ("EXIT, returning %d\n", ret);
-       return ret;
-}
-
-
-/**
- *     via_dsp_ioctl_space - get information about channel buffering
- *     @card: Private info for specified board
- *     @chan: pointer to channel-specific info
- *     @arg: user buffer for returned information
- *
- *     Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE.
- *
- *     Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_space (struct via_info *card,
-                               struct via_channel *chan,
-                               void __user *arg)
-{
-       audio_buf_info info;
-
-       via_chan_set_buffering(card, chan, -1);
-
-       info.fragstotal = chan->frag_number;
-       info.fragsize = chan->frag_size;
-
-       /* number of full fragments we can read/write without blocking */
-       info.fragments = atomic_read (&chan->n_frags);
-
-       if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0))
-               info.fragments--;
-
-       /* number of bytes that can be read or written immediately
-        * without blocking.
-        */
-       info.bytes = (info.fragments * chan->frag_size);
-       if (chan->slop_len % chan->frag_size > 0)
-               info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size);
-
-       DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",
-               info.fragstotal,
-               info.fragsize,
-               info.fragments,
-               info.bytes);
-
-       return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-/**
- *     via_dsp_ioctl_ptr - get information about hardware buffer ptr
- *     @card: Private info for specified board
- *     @chan: pointer to channel-specific info
- *     @arg: user buffer for returned information
- *
- *     Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR.
- *
- *     Locking: inside card->syscall_mutex
- */
-
-static int via_dsp_ioctl_ptr (struct via_info *card,
-                               struct via_channel *chan,
-                               void __user *arg)
-{
-       count_info info;
-
-       spin_lock_irq (&card->lock);
-
-       info.bytes = chan->bytes;
-       info.blocks = chan->n_irqs;
-       chan->n_irqs = 0;
-
-       spin_unlock_irq (&card->lock);
-
-       if (chan->is_active) {
-               unsigned long extra;
-               info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size;
-               extra = chan->frag_size - via_sg_offset(chan);
-               info.ptr += extra;
-               info.bytes += extra;
-       } else {
-               info.ptr = 0;
-       }
-
-       DPRINTK ("EXIT, returning bytes=%d, blocks=%d, ptr=%d\n",
-               info.bytes,
-               info.blocks,
-               info.ptr);
-
-       return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0;
-}
-
-
-static int via_dsp_ioctl_trigger (struct via_channel *chan, int val)
-{
-       int enable, do_something;
-
-       if (chan->is_record)
-               enable = (val & PCM_ENABLE_INPUT);
-       else
-               enable = (val & PCM_ENABLE_OUTPUT);
-
-       if (!chan->is_enabled && enable) {
-               do_something = 1;
-       } else if (chan->is_enabled && !enable) {
-               do_something = -1;
-       } else {
-               do_something = 0;
-       }
-
-       DPRINTK ("enable=%d, do_something=%d\n",
-                enable, do_something);
-
-       if (chan->is_active && do_something)
-               return -EINVAL;
-
-       if (do_something == 1) {
-               chan->is_enabled = 1;
-               via_chan_maybe_start (chan);
-               DPRINTK ("Triggering input\n");
-       }
-
-       else if (do_something == -1) {
-               chan->is_enabled = 0;
-               DPRINTK ("Setup input trigger\n");
-       }
-
-       return 0;
-}
-
-
-static int via_dsp_ioctl (struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg)
-{
-       int rc, rd=0, wr=0, val=0;
-       struct via_info *card;
-       struct via_channel *chan;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int __user *ip = (int __user *)arg;
-       void __user *p = (void __user *)arg;
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       if (file->f_mode & FMODE_WRITE)
-               wr = 1;
-       if (file->f_mode & FMODE_READ)
-               rd = 1;
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc)
-               return rc;
-       rc = -EINVAL;
-
-       switch (cmd) {
-
-       /* OSS API version.  XXX unverified */
-       case OSS_GETVERSION:
-               DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
-               rc = put_user (SOUND_VERSION, ip);
-               break;
-
-       /* list of supported PCM data formats */
-       case SNDCTL_DSP_GETFMTS:
-               DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
-                rc = put_user (AFMT_U8 | AFMT_S16_LE, ip);
-               break;
-
-       /* query or set current channel's PCM data format */
-       case SNDCTL_DSP_SETFMT:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SETFMT, val==%d\n", val);
-               if (val != AFMT_QUERY) {
-                       rc = 0;
-
-                       if (rd)
-                               rc = via_chan_set_fmt (card, &card->ch_in, val);
-
-                       if (rc >= 0 && wr)
-                               rc = via_chan_set_fmt (card, &card->ch_out, val);
-
-                       if (rc < 0)
-                               break;
-
-                       val = rc;
-               } else {
-                       if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||
-                           (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT)))
-                               val = AFMT_S16_LE;
-                       else
-                               val = AFMT_U8;
-               }
-               DPRINTK ("SETFMT EXIT, returning %d\n", val);
-                rc = put_user (val, ip);
-               break;
-
-       /* query or set number of channels (1=mono, 2=stereo, 4/6 for multichannel) */
-        case SNDCTL_DSP_CHANNELS:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_CHANNELS, val==%d\n", val);
-               if (val != 0) {
-                       rc = 0;
-
-                       if (rd)
-                               rc = via_chan_set_stereo (card, &card->ch_in, val);
-
-                       if (rc >= 0 && wr)
-                               rc = via_chan_set_stereo (card, &card->ch_out, val);
-
-                       if (rc < 0)
-                               break;
-
-                       val = rc;
-               } else {
-                       if (rd)
-                               val = card->ch_in.channels;
-                       else
-                               val = card->ch_out.channels;
-               }
-               DPRINTK ("CHANNELS EXIT, returning %d\n", val);
-                rc = put_user (val, ip);
-               break;
-
-       /* enable (val is not zero) or disable (val == 0) stereo */
-        case SNDCTL_DSP_STEREO:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_STEREO, val==%d\n", val);
-               rc = 0;
-
-               if (rd)
-                       rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);
-               if (rc >= 0 && wr)
-                       rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);
-
-               if (rc < 0)
-                       break;
-
-               val = rc - 1;
-
-               DPRINTK ("STEREO EXIT, returning %d\n", val);
-               rc = put_user(val, ip);
-               break;
-
-       /* query or set sampling rate */
-        case SNDCTL_DSP_SPEED:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SPEED, val==%d\n", val);
-               if (val < 0) {
-                       rc = -EINVAL;
-                       break;
-               }
-               if (val > 0) {
-                       rc = 0;
-
-                       if (rd)
-                               rc = via_chan_set_speed (card, &card->ch_in, val);
-                       if (rc >= 0 && wr)
-                               rc = via_chan_set_speed (card, &card->ch_out, val);
-
-                       if (rc < 0)
-                               break;
-
-                       val = rc;
-               } else {
-                       if (rd)
-                               val = card->ch_in.rate;
-                       else if (wr)
-                               val = card->ch_out.rate;
-                       else
-                               val = 0;
-               }
-               DPRINTK ("SPEED EXIT, returning %d\n", val);
-                rc = put_user (val, ip);
-               break;
-
-       /* wait until all buffers have been played, and then stop device */
-       case SNDCTL_DSP_SYNC:
-               DPRINTK ("DSP_SYNC\n");
-               rc = 0;
-               if (wr) {
-                       DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n");
-                       rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
-               }
-               break;
-
-       /* stop recording/playback immediately */
-        case SNDCTL_DSP_RESET:
-               DPRINTK ("DSP_RESET\n");
-               if (rd) {
-                       via_chan_clear (card, &card->ch_in);
-                       card->ch_in.frag_number = 0;
-                       card->ch_in.frag_size = 0;
-                       atomic_set(&card->ch_in.n_frags, 0);
-               }
-
-               if (wr) {
-                       via_chan_clear (card, &card->ch_out);
-                       card->ch_out.frag_number = 0;
-                       card->ch_out.frag_size = 0;
-                       atomic_set(&card->ch_out.n_frags, 0);
-               }
-
-               rc = 0;
-               break;
-
-       case SNDCTL_DSP_NONBLOCK:
-               file->f_flags |= O_NONBLOCK;
-               rc = 0;
-               break;
-
-       /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
-       case SNDCTL_DSP_GETCAPS:
-               DPRINTK ("DSP_GETCAPS\n");
-               rc = put_user(VIA_DSP_CAP, ip);
-               break;
-
-       /* obtain buffer fragment size */
-       case SNDCTL_DSP_GETBLKSIZE:
-               DPRINTK ("DSP_GETBLKSIZE\n");
-
-               if (rd) {
-                       via_chan_set_buffering(card, &card->ch_in, -1);
-                       rc = put_user(card->ch_in.frag_size, ip);
-               } else if (wr) {
-                       via_chan_set_buffering(card, &card->ch_out, -1);
-                       rc = put_user(card->ch_out.frag_size, ip);
-               }
-               break;
-
-       /* obtain information about input buffering */
-       case SNDCTL_DSP_GETISPACE:
-               DPRINTK ("DSP_GETISPACE\n");
-               if (rd)
-                       rc = via_dsp_ioctl_space (card, &card->ch_in, p);
-               break;
-
-       /* obtain information about output buffering */
-       case SNDCTL_DSP_GETOSPACE:
-               DPRINTK ("DSP_GETOSPACE\n");
-               if (wr)
-                       rc = via_dsp_ioctl_space (card, &card->ch_out, p);
-               break;
-
-       /* obtain information about input hardware pointer */
-       case SNDCTL_DSP_GETIPTR:
-               DPRINTK ("DSP_GETIPTR\n");
-               if (rd)
-                       rc = via_dsp_ioctl_ptr (card, &card->ch_in, p);
-               break;
-
-       /* obtain information about output hardware pointer */
-       case SNDCTL_DSP_GETOPTR:
-               DPRINTK ("DSP_GETOPTR\n");
-               if (wr)
-                       rc = via_dsp_ioctl_ptr (card, &card->ch_out, p);
-               break;
-
-       /* return number of bytes remaining to be played by DMA engine */
-       case SNDCTL_DSP_GETODELAY:
-               {
-               DPRINTK ("DSP_GETODELAY\n");
-
-               chan = &card->ch_out;
-
-               if (!wr)
-                       break;
-
-               if (chan->is_active) {
-
-                       val = chan->frag_number - atomic_read (&chan->n_frags);
-
-                       assert(val >= 0);
-                               
-                       if (val > 0) {
-                               val *= chan->frag_size;
-                               val -= chan->frag_size - via_sg_offset(chan);
-                       }
-                       val += chan->slop_len % chan->frag_size;
-               } else
-                       val = 0;
-
-               assert (val <= (chan->frag_size * chan->frag_number));
-
-               DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val);
-                rc = put_user (val, ip);
-               break;
-               }
-
-       /* handle the quick-start of a channel,
-        * or the notification that a quick-start will
-        * occur in the future
-        */
-       case SNDCTL_DSP_SETTRIGGER:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
-                       rd, wr, card->ch_in.is_active, card->ch_out.is_active,
-                       card->ch_in.is_enabled, card->ch_out.is_enabled);
-
-               rc = 0;
-
-               if (rd)
-                       rc = via_dsp_ioctl_trigger (&card->ch_in, val);
-
-               if (!rc && wr)
-                       rc = via_dsp_ioctl_trigger (&card->ch_out, val);
-
-               break;
-
-       case SNDCTL_DSP_GETTRIGGER:
-               val = 0;
-               if ((file->f_mode & FMODE_READ) && card->ch_in.is_enabled)
-                       val |= PCM_ENABLE_INPUT;
-               if ((file->f_mode & FMODE_WRITE) && card->ch_out.is_enabled)
-                       val |= PCM_ENABLE_OUTPUT;
-               rc = put_user(val, ip);
-               break;
-
-       /* Enable full duplex.  Since we do this as soon as we are opened
-        * with O_RDWR, this is mainly a no-op that always returns success.
-        */
-       case SNDCTL_DSP_SETDUPLEX:
-               DPRINTK ("DSP_SETDUPLEX\n");
-               if (!rd || !wr)
-                       break;
-               rc = 0;
-               break;
-
-       /* set fragment size.  implemented as a successful no-op for now */
-       case SNDCTL_DSP_SETFRAGMENT:
-               if (get_user(val, ip)) {
-                       rc = -EFAULT;
-                       break;
-               }
-               DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val);
-
-               if (rd)
-                       rc = via_chan_set_buffering(card, &card->ch_in, val);
-
-               if (wr)
-                       rc = via_chan_set_buffering(card, &card->ch_out, val);
-
-               DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n",
-                        val & 0xFFFF,
-                        val & 0xFFFF,
-                        (val >> 16) & 0xFFFF,
-                        (val >> 16) & 0xFFFF);
-
-               rc = 0;
-               break;
-
-       /* inform device of an upcoming pause in input (or output). */
-       case SNDCTL_DSP_POST:
-               DPRINTK ("DSP_POST\n");
-               if (wr) {
-                       if (card->ch_out.slop_len > 0)
-                               via_chan_flush_frag (&card->ch_out);
-                       via_chan_maybe_start (&card->ch_out);
-               }
-
-               rc = 0;
-               break;
-
-       /* not implemented */
-       default:
-               DPRINTK ("unhandled ioctl, cmd==%u, arg==%p\n",
-                        cmd, p);
-               break;
-       }
-
-       mutex_unlock(&card->syscall_mutex);
-       DPRINTK ("EXIT, returning %d\n", rc);
-       return rc;
-}
-
-
-static int via_dsp_open (struct inode *inode, struct file *file)
-{
-       int minor = iminor(inode);
-       struct via_info *card;
-       struct pci_dev *pdev = NULL;
-       struct via_channel *chan;
-       struct pci_driver *drvr;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-
-       DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode);
-
-       if (!(file->f_mode & (FMODE_READ | FMODE_WRITE))) {
-               DPRINTK ("EXIT, returning -EINVAL\n");
-               return -EINVAL;
-       }
-
-       card = NULL;
-       while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-               drvr = pci_dev_driver (pdev);
-               if (drvr == &via_driver) {
-                       assert (pci_get_drvdata (pdev) != NULL);
-
-                       card = pci_get_drvdata (pdev);
-                       DPRINTK ("dev_dsp = %d, minor = %d, assn = %d\n",
-                                card->dev_dsp, minor,
-                                (card->dev_dsp ^ minor) & ~0xf);
-
-                       if (((card->dev_dsp ^ minor) & ~0xf) == 0)
-                               goto match;
-               }
-       }
-
-       DPRINTK ("no matching %s found\n", card ? "minor" : "driver");
-       return -ENODEV;
-
-match:
-       pci_dev_put(pdev);
-       if (nonblock) {
-               if (!mutex_trylock(&card->open_mutex)) {
-                       DPRINTK ("EXIT, returning -EAGAIN\n");
-                       return -EAGAIN;
-               }
-       } else {
-               if (mutex_lock_interruptible(&card->open_mutex)) {
-                       DPRINTK ("EXIT, returning -ERESTARTSYS\n");
-                       return -ERESTARTSYS;
-               }
-       }
-
-       file->private_data = card;
-       DPRINTK ("file->f_mode == 0x%x\n", file->f_mode);
-
-       /* handle input from analog source */
-       if (file->f_mode & FMODE_READ) {
-               chan = &card->ch_in;
-
-               via_chan_init (card, chan);
-
-               /* why is this forced to 16-bit stereo in all drivers? */
-               chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
-               chan->channels = 2;
-
-               // TO DO - use FIFO: via_capture_fifo(card, 1);
-               via_chan_pcm_fmt (chan, 0);
-               via_set_rate (card->ac97, chan, 44100);
-       }
-
-       /* handle output to analog source */
-       if (file->f_mode & FMODE_WRITE) {
-               chan = &card->ch_out;
-
-               via_chan_init (card, chan);
-
-               if (file->f_mode & FMODE_READ) {
-                       /* if in duplex mode make the recording and playback channels
-                          have the same settings */
-                       chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
-                       chan->channels = 2;
-                       via_chan_pcm_fmt (chan, 0);
-                        via_set_rate (card->ac97, chan, 44100);
-               } else {
-                        if ((minor & 0xf) == SND_DEV_DSP16) {
-                               chan->pcm_fmt = VIA_PCM_FMT_16BIT;
-                               via_chan_pcm_fmt (chan, 0);
-                               via_set_rate (card->ac97, chan, 44100);
-                       } else {
-                               via_chan_pcm_fmt (chan, 1);
-                               via_set_rate (card->ac97, chan, 8000);
-                       }
-               }
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return nonseekable_open(inode, file);
-}
-
-
-static int via_dsp_release(struct inode *inode, struct file *file)
-{
-       struct via_info *card;
-       int nonblock = (file->f_flags & O_NONBLOCK);
-       int rc;
-
-       DPRINTK ("ENTER\n");
-
-       assert (file != NULL);
-       card = file->private_data;
-       assert (card != NULL);
-
-       rc = via_syscall_down (card, nonblock);
-       if (rc) {
-               DPRINTK ("EXIT (syscall_down error), rc=%d\n", rc);
-               return rc;
-       }
-
-       if (file->f_mode & FMODE_WRITE) {
-               rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
-               if (rc && rc != -ERESTARTSYS)   /* Nobody needs to know about ^C */
-                       printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc);
-
-               via_chan_free (card, &card->ch_out);
-               via_chan_buffer_free(card, &card->ch_out);
-       }
-
-       if (file->f_mode & FMODE_READ) {
-               via_chan_free (card, &card->ch_in);
-               via_chan_buffer_free (card, &card->ch_in);
-       }
-
-       mutex_unlock(&card->syscall_mutex);
-       mutex_unlock(&card->open_mutex);
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-/****************************************************************
- *
- * Chip setup and kernel registration
- *
- *
- */
-
-static int __devinit via_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
-{
-#ifdef CONFIG_MIDI_VIA82CXXX
-       u8 r42;
-#endif
-       int rc;
-       struct via_info *card;
-       static int printed_version;
-
-       DPRINTK ("ENTER\n");
-
-       if (printed_version++ == 0)
-               printk (KERN_INFO "Via 686a/8233/8235 audio driver " VIA_VERSION "\n");
-
-       rc = pci_enable_device (pdev);
-       if (rc)
-               goto err_out;
-
-       rc = pci_request_regions (pdev, "via82cxxx_audio");
-       if (rc)
-               goto err_out_disable;
-
-       rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-       if (rc)
-               goto err_out_res;
-       rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
-       if (rc)
-               goto err_out_res;
-
-       card = kmalloc (sizeof (*card), GFP_KERNEL);
-       if (!card) {
-               printk (KERN_ERR PFX "out of memory, aborting\n");
-               rc = -ENOMEM;
-               goto err_out_res;
-       }
-
-       pci_set_drvdata (pdev, card);
-
-       memset (card, 0, sizeof (*card));
-       card->pdev = pdev;
-       card->baseaddr = pci_resource_start (pdev, 0);
-       card->card_num = via_num_cards++;
-       spin_lock_init (&card->lock);
-       spin_lock_init (&card->ac97_lock);
-       mutex_init(&card->syscall_mutex);
-       mutex_init(&card->open_mutex);
-
-       /* we must init these now, in case the intr handler needs them */
-       via_chan_init_defaults (card, &card->ch_out);
-       via_chan_init_defaults (card, &card->ch_in);
-       via_chan_init_defaults (card, &card->ch_fm);
-
-       /* if BAR 2 is present, chip is Rev H or later,
-        * which means it has a few extra features */
-       if (pci_resource_start (pdev, 2) > 0)
-               card->rev_h = 1;
-               
-       /* Overkill for now, but more flexible done right */
-       
-       card->intmask = id->driver_data;
-       card->legacy = !card->intmask;
-       card->sixchannel = id->driver_data;
-       
-       if(card->sixchannel)
-               printk(KERN_INFO PFX "Six channel audio available\n");
-       if (pdev->irq < 1) {
-               printk (KERN_ERR PFX "invalid PCI IRQ %d, aborting\n", pdev->irq);
-               rc = -ENODEV;
-               goto err_out_kfree;
-       }
-
-       if (!(pci_resource_flags (pdev, 0) & IORESOURCE_IO)) {
-               printk (KERN_ERR PFX "unable to locate I/O resources, aborting\n");
-               rc = -ENODEV;
-               goto err_out_kfree;
-       }
-
-       pci_set_master(pdev);
-       
-       /*
-        * init AC97 mixer and codec
-        */
-       rc = via_ac97_init (card);
-       if (rc) {
-               printk (KERN_ERR PFX "AC97 init failed, aborting\n");
-               goto err_out_kfree;
-       }
-
-       /*
-        * init DSP device
-        */
-       rc = via_dsp_init (card);
-       if (rc) {
-               printk (KERN_ERR PFX "DSP device init failed, aborting\n");
-               goto err_out_have_mixer;
-       }
-
-       /*
-        * init and turn on interrupts, as the last thing we do
-        */
-       rc = via_interrupt_init (card);
-       if (rc) {
-               printk (KERN_ERR PFX "interrupt init failed, aborting\n");
-               goto err_out_have_dsp;
-       }
-
-       printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n",
-               card->card_num + 1, card->baseaddr, pdev->irq);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
-       /* Disable by default */
-       card->midi_info.io_base = 0;
-
-       if(card->legacy)
-       {
-               pci_read_config_byte (pdev, 0x42, &r42);
-               /* Disable MIDI interrupt */
-               pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK);
-               if (r42 & VIA_CR42_MIDI_ENABLE)
-               {
-                       if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */
-                               card->midi_info.io_base = pci_resource_start (pdev, 2);
-                       else /* Address selected by byte 0x43 */
-                       {
-                               u8 r43;
-                               pci_read_config_byte (pdev, 0x43, &r43);
-                               card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2);
-                       }
-
-                       card->midi_info.irq = -pdev->irq;
-                       if (probe_uart401(& card->midi_info, THIS_MODULE))
-                       {
-                               card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc;
-                               pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK);
-                               printk("Enabled Via MIDI\n");
-                       }
-               }
-       }
-#endif
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-
-err_out_have_dsp:
-       via_dsp_cleanup (card);
-
-err_out_have_mixer:
-       via_ac97_cleanup (card);
-
-err_out_kfree:
-#ifndef VIA_NDEBUG
-       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
-       kfree (card);
-
-err_out_res:
-       pci_release_regions (pdev);
-
-err_out_disable:
-       pci_disable_device (pdev);
-
-err_out:
-       pci_set_drvdata (pdev, NULL);
-       DPRINTK ("EXIT - returning %d\n", rc);
-       return rc;
-}
-
-
-static void __devexit via_remove_one (struct pci_dev *pdev)
-{
-       struct via_info *card;
-
-       DPRINTK ("ENTER\n");
-
-       assert (pdev != NULL);
-       card = pci_get_drvdata (pdev);
-       assert (card != NULL);
-
-#ifdef CONFIG_MIDI_VIA82CXXX
-       if (card->midi_info.io_base)
-               unload_uart401(&card->midi_info);
-#endif
-
-       free_irq (card->pdev->irq, card);
-       via_dsp_cleanup (card);
-       via_ac97_cleanup (card);
-
-#ifndef VIA_NDEBUG
-       memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */
-#endif
-       kfree (card);
-
-       pci_set_drvdata (pdev, NULL);
-
-       pci_release_regions (pdev);
-       pci_disable_device (pdev);
-       pci_set_power_state (pdev, 3); /* ...zzzzzz */
-
-       DPRINTK ("EXIT\n");
-       return;
-}
-
-
-/****************************************************************
- *
- * Driver initialization and cleanup
- *
- *
- */
-
-static int __init init_via82cxxx_audio(void)
-{
-       int rc;
-
-       DPRINTK ("ENTER\n");
-
-       rc = pci_register_driver (&via_driver);
-       if (rc) {
-               DPRINTK ("EXIT, returning %d\n", rc);
-               return rc;
-       }
-
-       DPRINTK ("EXIT, returning 0\n");
-       return 0;
-}
-
-
-static void __exit cleanup_via82cxxx_audio(void)
-{
-       DPRINTK ("ENTER\n");
-
-       pci_unregister_driver (&via_driver);
-
-       DPRINTK ("EXIT\n");
-}
-
-
-module_init(init_via82cxxx_audio);
-module_exit(cleanup_via82cxxx_audio);
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("DSP audio and mixer driver for Via 82Cxxx audio devices");
-MODULE_LICENSE("GPL");
-