Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfashe...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 May 2008 20:53:07 +0000 (13:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 May 2008 20:53:07 +0000 (13:53 -0700)
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2:
  ocfs2: Use GFP_NOFS in kmalloc during localalloc window move
  ocfs2: Allow uid/gid/perm changes of symlinks
  ocfs2/dlm: dlmdebug.c: make 2 functions static
  ocfs2: make struct o2cb_stack_ops static
  ocfs2: make struct ocfs2_control_device static
  ocfs2: Correct merge of 52f7c21 (Move /sys/o2cb to /sys/fs/o2cb)

342 files changed:
.gitignore
Documentation/hwmon/w83l785ts
Documentation/kdump/kdump.txt
Documentation/lguest/lguest.c
Documentation/scsi/ChangeLog.megaraid_sas
MAINTAINERS
Makefile
arch/alpha/kernel/osf_sys.c
arch/frv/mm/Makefile
arch/ia64/ia32/ia32_signal.c
arch/ia64/kernel/acpi.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/signal.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/time.c
arch/ia64/kernel/topology.c
arch/ia64/kvm/kvm-ia64.c
arch/m32r/Makefile
arch/m32r/defconfig [deleted file]
arch/m32r/kernel/vmlinux.lds.S
arch/m68knommu/kernel/asm-offsets.c
arch/m68knommu/kernel/entry.S
arch/m68knommu/kernel/setup.c
arch/m68knommu/kernel/signal.c
arch/m68knommu/kernel/traps.c
arch/m68knommu/kernel/vmlinux.lds.S
arch/m68knommu/platform/5206e/config.c
arch/m68knommu/platform/5272/config.c
arch/m68knommu/platform/528x/config.c
arch/m68knommu/platform/5307/config.c
arch/m68knommu/platform/coldfire/entry.S
arch/mips/kernel/binfmt_elfn32.c
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/irixioctl.c
arch/mips/kernel/kspd.c
arch/powerpc/kernel/time.c
arch/powerpc/platforms/cell/spufs/coredump.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/kernel/Makefile
arch/x86/kernel/genapic_64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/hpet.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/reboot.c
arch/x86/kvm/i8254.c
arch/x86/kvm/lapic.c
arch/x86/mach-voyager/voyager_cat.c
arch/x86/mm/highmem_32.c
arch/x86/mm/ioremap.c
arch/x86/mm/pageattr.c
arch/x86/pci/Makefile_32
arch/x86/pci/i386.c
arch/x86/vdso/vdso32-setup.c
block/blk-barrier.c
block/blk-core.c
block/blk-settings.c
block/blk-tag.c
block/bsg.c
block/elevator.c
block/scsi_ioctl.c
crypto/authenc.c
crypto/cryptd.c
crypto/eseqiv.c
drivers/acpi/video.c
drivers/base/base.h
drivers/base/class.c
drivers/base/cpu.c
drivers/base/driver.c
drivers/block/cciss.c
drivers/block/ub.c
drivers/block/virtio_blk.c
drivers/char/i8k.c
drivers/char/mmtimer.c
drivers/char/synclink.c
drivers/char/toshiba.c
drivers/char/tty_audit.c
drivers/char/tty_io.c
drivers/firewire/fw-sbp2.c
drivers/gpio/pca953x.c
drivers/hwmon/adt7473.c
drivers/hwmon/asb100.c
drivers/hwmon/lm75.c
drivers/hwmon/smsc47b397.c
drivers/hwmon/w83793.c
drivers/hwmon/w83l785ts.c
drivers/ide/ide-probe.c
drivers/ieee1394/nodemgr.c
drivers/isdn/hysdn/hysdn_procconf.c
drivers/lguest/lguest_device.c
drivers/lguest/lguest_user.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/devices/mtdram.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/pmc551.c
drivers/mtd/devices/slram.c
drivers/mtd/maps/uclinux.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/at91_nand.c
drivers/net/fec.c
drivers/net/fec.h
drivers/net/virtio_net.c
drivers/pcmcia/au1000_db1x00.c
drivers/pcmcia/au1000_generic.c
drivers/pcmcia/au1000_pb1x00.c
drivers/pcmcia/au1000_xxs1500.c
drivers/pcmcia/cardbus.c
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/i82092.c
drivers/pcmcia/omap_cf.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/pxa2xx_lubbock.c
drivers/pcmcia/pxa2xx_mainstone.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/sa1100_assabet.c
drivers/pcmcia/sa1100_badge4.c
drivers/pcmcia/sa1100_cerf.c
drivers/pcmcia/sa1100_jornada720.c
drivers/pcmcia/sa1100_neponset.c
drivers/pcmcia/sa1100_shannon.c
drivers/pcmcia/sa1100_simpad.c
drivers/pcmcia/soc_common.c
drivers/pcmcia/soc_common.h
drivers/pcmcia/socket_sysfs.c
drivers/pnp/pnpbios/rsparser.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_fsf.c
drivers/scsi/53c700.c
drivers/scsi/Kconfig
drivers/scsi/a100u2w.c
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aic94xx/aic94xx_init.c
drivers/scsi/constants.c
drivers/scsi/dpt/dpti_ioctl.h
drivers/scsi/dpt/dptsig.h
drivers/scsi/dpt/sys_info.h
drivers/scsi/dpt_i2o.c
drivers/scsi/dpti.h
drivers/scsi/gdth.c
drivers/scsi/hptiop.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/viosrp.h
drivers/scsi/initio.c
drivers/scsi/ipr.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_mbox.h
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/mvsas.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/qla1280.c
drivers/scsi/scsi.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_tgt_lib.c
drivers/scsi/u14-34f.c
drivers/serial/8250.c
drivers/serial/8250_early.c
drivers/serial/8250_pci.c
drivers/serial/jsm/jsm.h
drivers/serial/jsm/jsm_driver.c
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_s3c24xx.c
drivers/usb/Makefile
drivers/usb/atm/Kconfig
drivers/usb/c67x00/Makefile [new file with mode: 0644]
drivers/usb/c67x00/c67x00-drv.c [new file with mode: 0644]
drivers/usb/c67x00/c67x00-hcd.c [new file with mode: 0644]
drivers/usb/c67x00/c67x00-hcd.h [new file with mode: 0644]
drivers/usb/c67x00/c67x00-ll-hpi.c [new file with mode: 0644]
drivers/usb/c67x00/c67x00-sched.c [new file with mode: 0644]
drivers/usb/c67x00/c67x00.h [new file with mode: 0644]
drivers/usb/core/message.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/pxa27x_udc.c [new file with mode: 0644]
drivers/usb/gadget/pxa27x_udc.h [new file with mode: 0644]
drivers/usb/gadget/serial.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/isp1760-hcd.c [new file with mode: 0644]
drivers/usb/host/isp1760-hcd.h [new file with mode: 0644]
drivers/usb/host/isp1760-if.c [new file with mode: 0644]
drivers/usb/host/ohci-hub.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/misc/ldusb.c
drivers/usb/misc/usbtest.c
drivers/usb/serial/aircable.c
drivers/usb/serial/airprime.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/ch341.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/mos7840.c
drivers/usb/storage/Kconfig
drivers/usb/storage/cypress_atacb.c
drivers/usb/storage/isd200.c
drivers/usb/storage/libusual.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/virtio/virtio.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
fs/anon_inodes.c
fs/autofs4/expire.c
fs/autofs4/root.c
fs/autofs4/waitq.c
fs/compat.c
fs/debugfs/file.c
fs/dnotify.c
fs/eventfd.c
fs/eventpoll.c
fs/exec.c
fs/fcntl.c
fs/file.c
fs/file_table.c
fs/fuse/file.c
fs/jffs2/build.c
fs/jffs2/dir.c
fs/jffs2/erase.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/nodelist.h
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/super.c
fs/jffs2/wbuf.c
fs/jffs2/write.c
fs/jffs2/xattr.c
fs/locks.c
fs/open.c
fs/proc/array.c
fs/proc/base.c
fs/select.c
fs/signalfd.c
fs/sysfs/inode.c
fs/timerfd.c
fs/utimes.c
include/asm-arm/div64.h
include/asm-frv/unaligned.h
include/asm-generic/div64.h
include/asm-ia64/cpu.h
include/asm-ia64/dmi.h
include/asm-ia64/io.h
include/asm-ia64/thread_info.h
include/asm-m68k/div64.h
include/asm-m68knommu/dma.h
include/asm-m68knommu/param.h
include/asm-mips/div64.h
include/asm-mn10300/div64.h
include/asm-um/div64.h
include/asm-x86/div64.h
include/asm-x86/dmi.h
include/asm-x86/io_32.h
include/asm-x86/mach-default/mach_apic.h
include/asm-x86/processor.h
include/asm-x86/proto.h
include/crypto/scatterwalk.h
include/linux/Kbuild
include/linux/anon_inodes.h
include/linux/calc64.h [deleted file]
include/linux/clocksource.h
include/linux/compat.h
include/linux/device.h
include/linux/fdtable.h [new file with mode: 0644]
include/linux/file.h
include/linux/init_task.h
include/linux/io.h
include/linux/irq.h
include/linux/jiffies.h
include/linux/klist.h
include/linux/math64.h [new file with mode: 0644]
include/linux/module.h
include/linux/mtd/jedec.h [deleted file]
include/linux/mtd/mtd.h
include/linux/mtd/pmc551.h
include/linux/pci_ids.h
include/linux/poll.h
include/linux/quota.h
include/linux/string.h
include/linux/sysfs.h
include/linux/timex.h
include/linux/usb/c67x00.h [new file with mode: 0644]
include/linux/usb/ch9.h
include/linux/usb/gadget.h
include/linux/virtio.h
include/linux/virtio_blk.h
include/linux/virtio_config.h
include/linux/virtio_net.h
include/scsi/scsi.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_eh.h
include/scsi/scsi_host.h
kernel/compat.c
kernel/exit.c
kernel/fork.c
kernel/irq/manage.c
kernel/irq/spurious.c
kernel/kexec.c
kernel/kmod.c
kernel/module.c
kernel/posix-cpu-timers.c
kernel/ptrace.c
kernel/sched.c
kernel/sched_debug.c
kernel/softirq.c
kernel/time.c
kernel/time/ntp.c
kernel/time/timekeeping.c
kernel/workqueue.c
lib/devres.c
lib/div64.c
lib/idr.c
lib/klist.c
lib/kobject.c
lib/string.c
mm/memcontrol.c
mm/slub.c
mm/vmalloc.c
net/ipv4/tcp_cubic.c
net/ipv6/ipv6_sockglue.c
net/netfilter/xt_connbytes.c
scripts/kconfig/lxdialog/check-lxdialog.sh
security/selinux/hooks.c
virt/kvm/kvm_main.c

index 3016ed30526d4296e219d4ea9dc3ef7e23fe9f23..090b293b87792a815cf51aeccb590ec37c90cfa3 100644 (file)
@@ -41,6 +41,7 @@ include/linux/autoconf.h
 include/linux/compile.h
 include/linux/version.h
 include/linux/utsrelease.h
+include/linux/bounds.h
 
 # stgit generated dirs
 patches-*
index 1841cedc25b27d02d96d7dfac7b0763da909c8a9..bd1fa9d4468d9ba238c05c62cd562807c122e1ad 100644 (file)
@@ -33,7 +33,8 @@ Known Issues
 ------------
 
 On some systems (Asus), the BIOS is known to interfere with the driver
-and cause read errors. The driver will retry a given number of times
+and cause read errors. Or maybe the W83L785TS-S chip is simply unreliable,
+we don't really know. The driver will retry a given number of times
 (5 by default) and then give up, returning the old value (or 0 if
 there is no old value). It seems to work well enough so that you should
 not notice anything. Thanks to James Bolt for helping test this feature.
index d0ac72cc19ff8e29667e7a2c58e21d2d0cfafcb5..b8e52c0355d3bab81760adbf62d0c8a06a9ba52a 100644 (file)
@@ -245,6 +245,8 @@ The syntax is:
     crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset]
     range=start-[end]
 
+    'start' is inclusive and 'end' is exclusive.
+
 For example:
 
     crashkernel=512M-2G:64M,2G-:128M
@@ -253,10 +255,11 @@ This would mean:
 
     1) if the RAM is smaller than 512M, then don't reserve anything
        (this is the "rescue" case)
-    2) if the RAM size is between 512M and 2G, then reserve 64M
+    2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M
     3) if the RAM size is larger than 2G, then reserve 128M
 
 
+
 Boot into System Kernel
 =======================
 
index 4c1fc65a8b3d1c946965db4afc2a2dc08f82c44e..3be8ab2a886acf98e2b0a45ab3690fd20fc8bedc 100644 (file)
@@ -131,6 +131,9 @@ struct device
        /* Any queues attached to this device */
        struct virtqueue *vq;
 
+       /* Handle status being finalized (ie. feature bits stable). */
+       void (*ready)(struct device *me);
+
        /* Device-specific data. */
        void *priv;
 };
@@ -925,24 +928,40 @@ static void enable_fd(int fd, struct virtqueue *vq)
        write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
 }
 
-/* When the Guest asks us to reset a device, it's is fairly easy. */
-static void reset_device(struct device *dev)
+/* When the Guest tells us they updated the status field, we handle it. */
+static void update_device_status(struct device *dev)
 {
        struct virtqueue *vq;
 
-       verbose("Resetting device %s\n", dev->name);
-       /* Clear the status. */
-       dev->desc->status = 0;
+       /* This is a reset. */
+       if (dev->desc->status == 0) {
+               verbose("Resetting device %s\n", dev->name);
 
-       /* Clear any features they've acked. */
-       memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
-              dev->desc->feature_len);
+               /* Clear any features they've acked. */
+               memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
+                      dev->desc->feature_len);
 
-       /* Zero out the virtqueues. */
-       for (vq = dev->vq; vq; vq = vq->next) {
-               memset(vq->vring.desc, 0,
-                      vring_size(vq->config.num, getpagesize()));
-               vq->last_avail_idx = 0;
+               /* Zero out the virtqueues. */
+               for (vq = dev->vq; vq; vq = vq->next) {
+                       memset(vq->vring.desc, 0,
+                              vring_size(vq->config.num, getpagesize()));
+                       vq->last_avail_idx = 0;
+               }
+       } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
+               warnx("Device %s configuration FAILED", dev->name);
+       } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
+               unsigned int i;
+
+               verbose("Device %s OK: offered", dev->name);
+               for (i = 0; i < dev->desc->feature_len; i++)
+                       verbose(" %08x", get_feature_bits(dev)[i]);
+               verbose(", accepted");
+               for (i = 0; i < dev->desc->feature_len; i++)
+                       verbose(" %08x", get_feature_bits(dev)
+                               [dev->desc->feature_len+i]);
+
+               if (dev->ready)
+                       dev->ready(dev);
        }
 }
 
@@ -954,9 +973,9 @@ static void handle_output(int fd, unsigned long addr)
 
        /* Check each device and virtqueue. */
        for (i = devices.dev; i; i = i->next) {
-               /* Notifications to device descriptors reset the device. */
+               /* Notifications to device descriptors update device status. */
                if (from_guest_phys(addr) == i->desc) {
-                       reset_device(i);
+                       update_device_status(i);
                        return;
                }
 
@@ -1170,6 +1189,7 @@ static struct device *new_device(const char *name, u16 type, int fd,
        dev->handle_input = handle_input;
        dev->name = name;
        dev->vq = NULL;
+       dev->ready = NULL;
 
        /* Append to device list.  Prepending to a single-linked list is
         * easier, but the user expects the devices to be arranged on the bus
@@ -1398,7 +1418,7 @@ static bool service_io(struct device *dev)
        struct vblk_info *vblk = dev->priv;
        unsigned int head, out_num, in_num, wlen;
        int ret;
-       struct virtio_blk_inhdr *in;
+       u8 *in;
        struct virtio_blk_outhdr *out;
        struct iovec iov[dev->vq->vring.num];
        off64_t off;
@@ -1416,7 +1436,7 @@ static bool service_io(struct device *dev)
                     head, out_num, in_num);
 
        out = convert(&iov[0], struct virtio_blk_outhdr);
-       in = convert(&iov[out_num+in_num-1], struct virtio_blk_inhdr);
+       in = convert(&iov[out_num+in_num-1], u8);
        off = out->sector * 512;
 
        /* The block device implements "barriers", where the Guest indicates
@@ -1430,7 +1450,7 @@ static bool service_io(struct device *dev)
         * It'd be nice if we supported eject, for example, but we don't. */
        if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
                fprintf(stderr, "Scsi commands unsupported\n");
-               in->status = VIRTIO_BLK_S_UNSUPP;
+               *in = VIRTIO_BLK_S_UNSUPP;
                wlen = sizeof(*in);
        } else if (out->type & VIRTIO_BLK_T_OUT) {
                /* Write */
@@ -1453,7 +1473,7 @@ static bool service_io(struct device *dev)
                        errx(1, "Write past end %llu+%u", off, ret);
                }
                wlen = sizeof(*in);
-               in->status = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
+               *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
        } else {
                /* Read */
 
@@ -1466,10 +1486,10 @@ static bool service_io(struct device *dev)
                verbose("READ from sector %llu: %i\n", out->sector, ret);
                if (ret >= 0) {
                        wlen = sizeof(*in) + ret;
-                       in->status = VIRTIO_BLK_S_OK;
+                       *in = VIRTIO_BLK_S_OK;
                } else {
                        wlen = sizeof(*in);
-                       in->status = VIRTIO_BLK_S_IOERR;
+                       *in = VIRTIO_BLK_S_IOERR;
                }
        }
 
index 91c81db0ba711c3594dbcbe8b6aa930bacb06b1f..716fcc1cafb5cac5f1e13aa6be971825687a2f04 100644 (file)
@@ -1,3 +1,25 @@
+1 Release Date    : Mon. March 10 11:02:31 PDT 2008 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Sumant Patro
+                       Bo Yang
+
+2 Current Version : 00.00.03.20-RC1
+3 Older Version   : 00.00.03.16
+
+1. Rollback the sense info implementation
+       Sense buffer ptr data type in the ioctl path is reverted back
+       to u32 * as in previous versions of driver.
+
+2. Fixed the driver frame count.
+       When Driver sent wrong frame count to firmware.  As this
+       particular command is sent to drive, FW is seeing continuous
+       chip resets and so the command will timeout.
+
+3. Add the new controller(1078DE) support to the driver
+       and Increase the max_wait to 60 from 10 in the controller
+       operational status.  With this max_wait increase, driver will
+       make sure the FW will   finish the pending cmd for KDUMP case.
+
 1 Release Date    : Thur. Nov. 07 16:30:43 PST 2007 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Sumant Patro
index c3a533d5d3824ce0bd7d4c78e1a5d5a6824e1078..93547d3d04b95534791cef925a9f4a99600cf97e 100644 (file)
@@ -1196,9 +1196,9 @@ S:        Maintained
 
 CPUSETS
 P:     Paul Jackson
-P:     Simon Derr
+P:     Paul Menage
 M:     pj@sgi.com
-M:     simon.derr@bull.net
+M:     menage@google.com
 L:     linux-kernel@vger.kernel.org
 W:     http://www.bullopensource.org/cpuset/
 S:     Supported
@@ -1557,6 +1557,14 @@ M:       raisch@de.ibm.com
 L:     general@lists.openfabrics.org
 S:     Supported
 
+EMBEDDED LINUX
+P:     Paul Gortmaker
+M:     paul.gortmaker@windriver.com
+P      David Woodhouse
+M:     dwmw2@infradead.org
+L:     linux-embedded@vger.kernel.org
+S:     Maintained
+
 EMULEX LPFC FC SCSI DRIVER
 P:     James Smart
 M:     james.smart@emulex.com
@@ -4043,6 +4051,12 @@ L:      linux-usb@vger.kernel.org
 S:     Maintained
 W:     http://www.kroah.com/linux-usb/
 
+USB CYPRESS C67X00 DRIVER
+P:     Peter Korsgaard
+M:     jacmet@sunsite.dk
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+
 USB DAVICOM DM9601 DRIVER
 P:     Peter Korsgaard
 M:     jacmet@sunsite.dk
index d3634cd6fe35bde2a8ef73835e9f6f2559087dab..5cf8258195331a4dbdddff08b8d68642638eea57 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -794,7 +794,7 @@ endif # ifdef CONFIG_KALLSYMS
 quiet_cmd_vmlinux-modpost = LD      $@
       cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@                          \
         $(vmlinux-init) --start-group $(vmlinux-main) --end-group             \
-        $(filter-out $(vmlinux-init) $(vmlinux-main) $(vmlinux-lds) FORCE ,$^)
+        $(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
 define rule_vmlinux-modpost
        :
        +$(call cmd,vmlinux-modpost)
@@ -818,7 +818,9 @@ endif
 ifdef CONFIG_KALLSYMS
 .tmp_vmlinux1: vmlinux.o
 endif
-vmlinux.o: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE
+
+modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))
+vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
        $(call if_changed_rule,vmlinux-modpost)
 
 # The actual objects are generated when descending, 
index 9fee37e2596f34fe8d3c22558b87d248396b4dca..32ca1b9273078d7025466075e677a59e34938b33 100644 (file)
@@ -981,27 +981,18 @@ asmlinkage int
 osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
           struct timeval32 __user *tvp)
 {
-       fd_set_bits fds;
-       char *bits;
-       size_t size;
-       long timeout;
-       int ret = -EINVAL;
-       struct fdtable *fdt;
-       int max_fds;
-
-       timeout = MAX_SCHEDULE_TIMEOUT;
+       s64 timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
                time_t sec, usec;
 
                if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
                    || __get_user(sec, &tvp->tv_sec)
                    || __get_user(usec, &tvp->tv_usec)) {
-                       ret = -EFAULT;
-                       goto out_nofds;
+                       return -EFAULT;
                }
 
                if (sec < 0 || usec < 0)
-                       goto out_nofds;
+                       return -EINVAL;
 
                if ((unsigned long) sec < MAX_SELECT_SECONDS) {
                        timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
@@ -1009,60 +1000,8 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
                }
        }
 
-       rcu_read_lock();
-       fdt = files_fdtable(current->files);
-       max_fds = fdt->max_fds;
-       rcu_read_unlock();
-       if (n < 0 || n > max_fds)
-               goto out_nofds;
-
-       /*
-        * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-        * since we used fdset we need to allocate memory in units of
-        * long-words. 
-        */
-       ret = -ENOMEM;
-       size = FDS_BYTES(n);
-       bits = kmalloc(6 * size, GFP_KERNEL);
-       if (!bits)
-               goto out_nofds;
-       fds.in      = (unsigned long *)  bits;
-       fds.out     = (unsigned long *) (bits +   size);
-       fds.ex      = (unsigned long *) (bits + 2*size);
-       fds.res_in  = (unsigned long *) (bits + 3*size);
-       fds.res_out = (unsigned long *) (bits + 4*size);
-       fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-       if ((ret = get_fd_set(n, inp->fds_bits, fds.in)) ||
-           (ret = get_fd_set(n, outp->fds_bits, fds.out)) ||
-           (ret = get_fd_set(n, exp->fds_bits, fds.ex)))
-               goto out;
-       zero_fd_set(n, fds.res_in);
-       zero_fd_set(n, fds.res_out);
-       zero_fd_set(n, fds.res_ex);
-
-       ret = do_select(n, &fds, &timeout);
-
        /* OSF does not copy back the remaining time.  */
-
-       if (ret < 0)
-               goto out;
-       if (!ret) {
-               ret = -ERESTARTNOHAND;
-               if (signal_pending(current))
-                       goto out;
-               ret = 0;
-       }
-
-       if (set_fd_set(n, inp->fds_bits, fds.res_in) ||
-           set_fd_set(n, outp->fds_bits, fds.res_out) ||
-           set_fd_set(n, exp->fds_bits, fds.res_ex))
-               ret = -EFAULT;
-
- out:
-       kfree(bits);
- out_nofds:
-       return ret;
+       return core_sys_select(n, inp, outp, exp, &timeout);
 }
 
 struct rusage32 {
index fb8b1d860f46b1f71e60684534c38aa16f2812c6..1bca5ab8a6ab085aa35fdb1c14574b7dc2adb7a7 100644 (file)
@@ -6,4 +6,4 @@ obj-y := init.o kmap.o
 
 obj-$(CONFIG_MMU) += \
        pgalloc.o highmem.o fault.o extable.o cache-page.o tlb-flush.o tlb-miss.o \
-       mmu-context.o dma-alloc.o unaligned.o elf-fdpic.o
+       mmu-context.o dma-alloc.o elf-fdpic.o
index 256a7faeda0787fc7ba6df9f48d0899dc0add99a..b763ca19ef173f26a642910124cbf30f30b3ad43 100644 (file)
@@ -463,7 +463,7 @@ sys32_sigsuspend (int history0, int history1, old_sigset_t mask)
 
        current->state = TASK_INTERRUPTIBLE;
        schedule();
-       set_thread_flag(TIF_RESTORE_SIGMASK);
+       set_restore_sigmask();
        return -ERESTARTNOHAND;
 }
 
index c7467f863c7af5c99312767f8f176628568ab96f..19709a0796351e408a30fcd74ebc3a6ac92ec279 100644 (file)
@@ -966,7 +966,7 @@ acpi_map_iosapics (void)
 fs_initcall(acpi_map_iosapics);
 #endif                         /* CONFIG_ACPI_NUMA */
 
-int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
+int __ref acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 {
        int err;
 
index 6dee579f205fc451bcffbcbaddd0c370b6d35104..7fd18f54c0568980238cc75a7810ea51de4a4308 100644 (file)
@@ -183,10 +183,10 @@ void fixup_irqs(void)
 {
        unsigned int irq;
        extern void ia64_process_pending_intr(void);
-       extern void ia64_disable_timer(void);
        extern volatile int time_keeper_id;
 
-       ia64_disable_timer();
+       /* Mask ITV to disable timer */
+       ia64_set_itv(1 << 16);
 
        /*
         * Find a new timesync master
index 396004e8cd1432af8fa1440ea0e2b93c385175bd..4547a2092af9d4717273883247b6e854749c819d 100644 (file)
@@ -1053,7 +1053,7 @@ static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block palinfo_cpu_notifier __cpuinitdata =
+static struct notifier_block __refdata palinfo_cpu_notifier =
 {
        .notifier_call = palinfo_cpu_callback,
        .priority = 0,
index 7fbb51e10bbe04e70c2cc66570400f3569f3804c..c1ad27de2dd2080e0bdea8a845147fcc6f855dba 100644 (file)
@@ -867,7 +867,7 @@ pfm_rvfree(void *mem, unsigned long size)
 }
 
 static pfm_context_t *
-pfm_context_alloc(void)
+pfm_context_alloc(int ctx_flags)
 {
        pfm_context_t *ctx;
 
@@ -878,6 +878,46 @@ pfm_context_alloc(void)
        ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL);
        if (ctx) {
                DPRINT(("alloc ctx @%p\n", ctx));
+
+               /*
+                * init context protection lock
+                */
+               spin_lock_init(&ctx->ctx_lock);
+
+               /*
+                * context is unloaded
+                */
+               ctx->ctx_state = PFM_CTX_UNLOADED;
+
+               /*
+                * initialization of context's flags
+                */
+               ctx->ctx_fl_block       = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
+               ctx->ctx_fl_system      = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
+               ctx->ctx_fl_no_msg      = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
+               /*
+                * will move to set properties
+                * ctx->ctx_fl_excl_idle   = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
+                */
+
+               /*
+                * init restart semaphore to locked
+                */
+               init_completion(&ctx->ctx_restart_done);
+
+               /*
+                * activation is used in SMP only
+                */
+               ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
+               SET_LAST_CPU(ctx, -1);
+
+               /*
+                * initialize notification message queue
+                */
+               ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
+               init_waitqueue_head(&ctx->ctx_msgq_wait);
+               init_waitqueue_head(&ctx->ctx_zombieq);
+
        }
        return ctx;
 }
@@ -2165,28 +2205,21 @@ static struct dentry_operations pfmfs_dentry_operations = {
 };
 
 
-static int
-pfm_alloc_fd(struct file **cfile)
+static struct file *
+pfm_alloc_file(pfm_context_t *ctx)
 {
-       int fd, ret = 0;
-       struct file *file = NULL;
-       struct inode * inode;
+       struct file *file;
+       struct inode *inode;
+       struct dentry *dentry;
        char name[32];
        struct qstr this;
 
-       fd = get_unused_fd();
-       if (fd < 0) return -ENFILE;
-
-       ret = -ENFILE;
-
-       file = get_empty_filp();
-       if (!file) goto out;
-
        /*
         * allocate a new inode
         */
        inode = new_inode(pfmfs_mnt->mnt_sb);
-       if (!inode) goto out;
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
 
        DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode));
 
@@ -2199,59 +2232,28 @@ pfm_alloc_fd(struct file **cfile)
        this.len  = strlen(name);
        this.hash = inode->i_ino;
 
-       ret = -ENOMEM;
-
        /*
         * allocate a new dcache entry
         */
-       file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
-       if (!file->f_path.dentry) goto out;
+       dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
+       if (!dentry) {
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
 
-       file->f_path.dentry->d_op = &pfmfs_dentry_operations;
+       dentry->d_op = &pfmfs_dentry_operations;
+       d_add(dentry, inode);
 
-       d_add(file->f_path.dentry, inode);
-       file->f_path.mnt = mntget(pfmfs_mnt);
-       file->f_mapping = inode->i_mapping;
+       file = alloc_file(pfmfs_mnt, dentry, FMODE_READ, &pfm_file_ops);
+       if (!file) {
+               dput(dentry);
+               return ERR_PTR(-ENFILE);
+       }
 
-       file->f_op    = &pfm_file_ops;
-       file->f_mode  = FMODE_READ;
        file->f_flags = O_RDONLY;
-       file->f_pos   = 0;
-
-       /*
-        * may have to delay until context is attached?
-        */
-       fd_install(fd, file);
-
-       /*
-        * the file structure we will use
-        */
-       *cfile = file;
-
-       return fd;
-out:
-       if (file) put_filp(file);
-       put_unused_fd(fd);
-       return ret;
-}
-
-static void
-pfm_free_fd(int fd, struct file *file)
-{
-       struct files_struct *files = current->files;
-       struct fdtable *fdt;
+       file->private_data = ctx;
 
-       /* 
-        * there ie no fd_uninstall(), so we do it here
-        */
-       spin_lock(&files->file_lock);
-       fdt = files_fdtable(files);
-       rcu_assign_pointer(fdt->fd[fd], NULL);
-       spin_unlock(&files->file_lock);
-
-       if (file)
-               put_filp(file);
-       put_unused_fd(fd);
+       return file;
 }
 
 static int
@@ -2475,6 +2477,7 @@ pfm_setup_buffer_fmt(struct task_struct *task, struct file *filp, pfm_context_t
 
        /* link buffer format and context */
        ctx->ctx_buf_fmt = fmt;
+       ctx->ctx_fl_is_sampling = 1; /* assume record() is defined */
 
        /*
         * check if buffer format wants to use perfmon buffer allocation/mapping service
@@ -2669,78 +2672,45 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
 {
        pfarg_context_t *req = (pfarg_context_t *)arg;
        struct file *filp;
+       struct path path;
        int ctx_flags;
+       int fd;
        int ret;
 
        /* let's check the arguments first */
        ret = pfarg_is_sane(current, req);
-       if (ret < 0) return ret;
+       if (ret < 0)
+               return ret;
 
        ctx_flags = req->ctx_flags;
 
        ret = -ENOMEM;
 
-       ctx = pfm_context_alloc();
-       if (!ctx) goto error;
+       fd = get_unused_fd();
+       if (fd < 0)
+               return fd;
 
-       ret = pfm_alloc_fd(&filp);
-       if (ret < 0) goto error_file;
+       ctx = pfm_context_alloc(ctx_flags);
+       if (!ctx)
+               goto error;
 
-       req->ctx_fd = ctx->ctx_fd = ret;
+       filp = pfm_alloc_file(ctx);
+       if (IS_ERR(filp)) {
+               ret = PTR_ERR(filp);
+               goto error_file;
+       }
 
-       /*
-        * attach context to file
-        */
-       filp->private_data = ctx;
+       req->ctx_fd = ctx->ctx_fd = fd;
 
        /*
         * does the user want to sample?
         */
        if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) {
                ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req);
-               if (ret) goto buffer_error;
+               if (ret)
+                       goto buffer_error;
        }
 
-       /*
-        * init context protection lock
-        */
-       spin_lock_init(&ctx->ctx_lock);
-
-       /*
-        * context is unloaded
-        */
-       ctx->ctx_state = PFM_CTX_UNLOADED;
-
-       /*
-        * initialization of context's flags
-        */
-       ctx->ctx_fl_block       = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
-       ctx->ctx_fl_system      = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
-       ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */
-       ctx->ctx_fl_no_msg      = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
-       /*
-        * will move to set properties
-        * ctx->ctx_fl_excl_idle   = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
-        */
-
-       /*
-        * init restart semaphore to locked
-        */
-       init_completion(&ctx->ctx_restart_done);
-
-       /*
-        * activation is used in SMP only
-        */
-       ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
-       SET_LAST_CPU(ctx, -1);
-
-       /*
-        * initialize notification message queue
-        */
-       ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
-       init_waitqueue_head(&ctx->ctx_msgq_wait);
-       init_waitqueue_head(&ctx->ctx_zombieq);
-
        DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n",
                ctx,
                ctx_flags,
@@ -2755,10 +2725,14 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
         */
        pfm_reset_pmu_state(ctx);
 
+       fd_install(fd, filp);
+
        return 0;
 
 buffer_error:
-       pfm_free_fd(ctx->ctx_fd, filp);
+       path = filp->f_path;
+       put_filp(filp);
+       path_put(&path);
 
        if (ctx->ctx_buf_fmt) {
                pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs);
@@ -2767,6 +2741,7 @@ error_file:
        pfm_context_free(ctx);
 
 error:
+       put_unused_fd(fd);
        return ret;
 }
 
index 5740296c35afa3d597e8fd041db4385ff628f268..19c5a78636fc92fd78a38642063107da1895bd59 100644 (file)
@@ -464,7 +464,7 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
        if (!user_mode(&scr->pt))
                return;
 
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+       if (current_thread_info()->status & TS_RESTORE_SIGMASK)
                oldset = &current->saved_sigmask;
        else
                oldset = &current->blocked;
@@ -530,12 +530,13 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
                 * continue to iterate in this loop so we can deliver the SIGSEGV...
                 */
                if (handle_signal(signr, &ka, &info, oldset, scr)) {
-                       /* a signal was successfully delivered; the saved
+                       /*
+                        * A signal was successfully delivered; the saved
                         * sigmask will have been stored in the signal frame,
                         * and will be restored by sigreturn, so we can simply
-                        * clear the TIF_RESTORE_SIGMASK flag */
-                       if (test_thread_flag(TIF_RESTORE_SIGMASK))
-                               clear_thread_flag(TIF_RESTORE_SIGMASK);
+                        * clear the TS_RESTORE_SIGMASK flag.
+                        */
+                       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                        return;
                }
        }
@@ -566,8 +567,8 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall)
 
        /* if there's no signal to deliver, we just put the saved sigmask
         * back */
-       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-               clear_thread_flag(TIF_RESTORE_SIGMASK);
+       if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+               current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
        }
 }
index 9a9d4c4893305848dc91ded242577d55ff3ef13a..983296f1c813a3baeb34435258b9ff8af737a172 100644 (file)
@@ -98,8 +98,33 @@ unlock_ipi_calllock(void)
        spin_unlock_irq(&call_lock);
 }
 
+static inline void
+handle_call_data(void)
+{
+       struct call_data_struct *data;
+       void (*func)(void *info);
+       void *info;
+       int wait;
+
+       /* release the 'pointer lock' */
+       data = (struct call_data_struct *)call_data;
+       func = data->func;
+       info = data->info;
+       wait = data->wait;
+
+       mb();
+       atomic_inc(&data->started);
+       /* At this point the structure may be gone unless wait is true. */
+       (*func)(info);
+
+       /* Notify the sending CPU that the task is done. */
+       mb();
+       if (wait)
+               atomic_inc(&data->finished);
+}
+
 static void
-stop_this_cpu (void)
+stop_this_cpu(void)
 {
        /*
         * Remove this CPU:
@@ -138,44 +163,21 @@ handle_IPI (int irq, void *dev_id)
                        ops &= ~(1 << which);
 
                        switch (which) {
-                             case IPI_CALL_FUNC:
-                             {
-                                     struct call_data_struct *data;
-                                     void (*func)(void *info);
-                                     void *info;
-                                     int wait;
-
-                                     /* release the 'pointer lock' */
-                                     data = (struct call_data_struct *) call_data;
-                                     func = data->func;
-                                     info = data->info;
-                                     wait = data->wait;
-
-                                     mb();
-                                     atomic_inc(&data->started);
-                                     /*
-                                      * At this point the structure may be gone unless
-                                      * wait is true.
-                                      */
-                                     (*func)(info);
-
-                                     /* Notify the sending CPU that the task is done.  */
-                                     mb();
-                                     if (wait)
-                                             atomic_inc(&data->finished);
-                             }
-                             break;
-
-                             case IPI_CPU_STOP:
+                       case IPI_CALL_FUNC:
+                               handle_call_data();
+                               break;
+
+                       case IPI_CPU_STOP:
                                stop_this_cpu();
                                break;
 #ifdef CONFIG_KEXEC
-                             case IPI_KDUMP_CPU_STOP:
+                       case IPI_KDUMP_CPU_STOP:
                                unw_init_running(kdump_cpu_freeze, NULL);
                                break;
 #endif
-                             default:
-                               printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
+                       default:
+                               printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
+                                               this_cpu, which);
                                break;
                        }
                } while (ops);
index 48e15a51782f617fae2c1fbc6f8964d70ccb870c..8c73643f2d664a5d9f8dd103ed67e5e5bbf037d4 100644 (file)
@@ -379,11 +379,6 @@ static struct irqaction timer_irqaction = {
        .name =         "timer"
 };
 
-void __devinit ia64_disable_timer(void)
-{
-       ia64_set_itv(1 << 16);
-}
-
 void __init
 time_init (void)
 {
index abb17a613b172f2feac86f38981c255d226864ac..26228e2d01ae472bcab1e5917b0c973d826f6f3a 100644 (file)
@@ -36,9 +36,11 @@ void arch_fix_phys_package_id(int num, u32 slot)
 }
 EXPORT_SYMBOL_GPL(arch_fix_phys_package_id);
 
-int arch_register_cpu(int num)
+
+#ifdef CONFIG_HOTPLUG_CPU
+int __ref arch_register_cpu(int num)
 {
-#if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU)
+#ifdef CONFIG_ACPI
        /*
         * If CPEI can be re-targetted or if this is not
         * CPEI target, then it is hotpluggable
@@ -47,19 +49,21 @@ int arch_register_cpu(int num)
                sysfs_cpus[num].cpu.hotpluggable = 1;
        map_cpu_to_node(num, node_cpuid[num].nid);
 #endif
-
        return register_cpu(&sysfs_cpus[num].cpu, num);
 }
-
-#ifdef CONFIG_HOTPLUG_CPU
+EXPORT_SYMBOL(arch_register_cpu);
 
 void arch_unregister_cpu(int num)
 {
        unregister_cpu(&sysfs_cpus[num].cpu);
        unmap_cpu_from_node(num, cpu_to_node(num));
 }
-EXPORT_SYMBOL(arch_register_cpu);
 EXPORT_SYMBOL(arch_unregister_cpu);
+#else
+static int __init arch_register_cpu(int num)
+{
+       return register_cpu(&sysfs_cpus[num].cpu, num);
+}
 #endif /*CONFIG_HOTPLUG_CPU*/
 
 
index 6df0732401353f56524d1ee1d60ef2a9358bae8d..318b811006236fe08b7508e3a16f6ccaa326a28d 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * kvm_ia64.c: Basic KVM suppport On Itanium series processors
  *
@@ -431,7 +430,7 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
        if (itc_diff < 0)
                itc_diff = -itc_diff;
 
-       expires = div64_64(itc_diff, cyc_per_usec);
+       expires = div64_u64(itc_diff, cyc_per_usec);
        kt = ktime_set(0, 1000 * expires);
        vcpu->arch.ht_active = 1;
        hrtimer_start(p_ht, kt, HRTIMER_MODE_ABS);
index 4072a07ebf8e301af8fa34fa788e5c5ece63eccb..469766b24e2286ca3495b39a9dbf194dd83ca423 100644 (file)
@@ -5,6 +5,8 @@
 # architecture-specific flags and dependencies.
 #
 
+KBUILD_DEFCONFIG := m32700ut.smp_defconfig
+
 LDFLAGS                :=
 OBJCOPYFLAGS   := -O binary -R .note -R .comment -S
 LDFLAGS_vmlinux        :=
diff --git a/arch/m32r/defconfig b/arch/m32r/defconfig
deleted file mode 100644 (file)
index af3b981..0000000
+++ /dev/null
@@ -1,863 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc1
-# Wed Aug  1 17:22:35 2007
-#
-CONFIG_M32R=y
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_ZONE_DMA=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_NO_IOPORT=y
-CONFIG_NO_DMA=y
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCK_KERNEL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=15
-# CONFIG_CPUSETS is not set
-CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
-CONFIG_SYSCTL_SYSCALL=y
-# CONFIG_KALLSYMS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-# CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
-# CONFIG_EPOLL is not set
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-# CONFIG_BLK_DEV_BSG is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-
-#
-# Processor type and features
-#
-# CONFIG_PLAT_MAPPI is not set
-# CONFIG_PLAT_USRV is not set
-CONFIG_PLAT_M32700UT=y
-# CONFIG_PLAT_OPSPUT is not set
-# CONFIG_PLAT_OAKS32R is not set
-# CONFIG_PLAT_MAPPI2 is not set
-# CONFIG_PLAT_MAPPI3 is not set
-# CONFIG_PLAT_M32104UT is not set
-CONFIG_CHIP_M32700=y
-# CONFIG_CHIP_M32102 is not set
-# CONFIG_CHIP_M32104 is not set
-# CONFIG_CHIP_VDEC2 is not set
-# CONFIG_CHIP_OPSP is not set
-CONFIG_MMU=y
-CONFIG_TLB_ENTRIES=32
-CONFIG_ISA_M32R2=y
-CONFIG_ISA_DSP_LEVEL2=y
-CONFIG_ISA_DUAL_ISSUE=y
-CONFIG_BUS_CLOCK=50000000
-CONFIG_TIMER_DIVIDE=128
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_MEMORY_START=0x08000000
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_NOHIGHMEM=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-# CONFIG_FLATMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM_MANUAL=y
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-CONFIG_IRAM_START=0x00f00000
-CONFIG_IRAM_SIZE=0x00080000
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_PREEMPT=y
-CONFIG_SMP=y
-# CONFIG_CHIP_M32700_TS1 is not set
-CONFIG_NR_CPUS=2
-CONFIG_NODES_SHIFT=1
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_ISA is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_SCTP is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
-# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-# CONFIG_MTD_CHAR is not set
-CONFIG_MTD_BLKDEVS=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-# CONFIG_RFD_FTL is not set
-# CONFIG_SSFDC is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_GEN_PROBE=m
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-# CONFIG_MTD_CFI_NOSWAP is not set
-CONFIG_MTD_CFI_BE_BYTE_SWAP=y
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-CONFIG_MTD_CFI_GEOMETRY=y
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-# CONFIG_MTD_CFI_I2 is not set
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_OTP is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_CFI_AMDSTD=m
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=m
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_PLATRAM is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_ONENAND is not set
-
-#
-# UBI - Unsorted block images
-#
-# CONFIG_MTD_UBI is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_CDROM_PKTCDVD is not set
-CONFIG_ATA_OVER_ETH=m
-CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_PROC_FS=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=m
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-CONFIG_CHR_DEV_SG=m
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_MD is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_PHYLIB is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_SMC91X=y
-# CONFIG_NE2000 is not set
-CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP 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
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_M32R_SIO=y
-CONFIG_SERIAL_M32R_SIO_CONSOLE=y
-CONFIG_SERIAL_M32R_PLDSIO=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
-# CONFIG_RTC is not set
-CONFIG_DS1302=y
-# CONFIG_R3964 is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_ABITUGURU3 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-
-#
-# Multimedia devices
-#
-CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-CONFIG_VIDEO_V4L2=y
-CONFIG_VIDEO_CAPTURE_DRIVERS=y
-# CONFIG_VIDEO_ADV_DEBUG is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_CPIA is not set
-CONFIG_VIDEO_M32R_AR=m
-CONFIG_VIDEO_M32R_AR_M64278=m
-CONFIG_RADIO_ADAPTERS=y
-# CONFIG_DVB_CORE is not set
-CONFIG_DAB=y
-
-#
-# Graphics support
-#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-CONFIG_FB=y
-CONFIG_FIRMWARE_EDID=y
-# CONFIG_FB_DDC is not set
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_SYS_FOPS is not set
-CONFIG_FB_DEFERRED_IO=y
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frame buffer hardware drivers
-#
-CONFIG_FB_S1D13XXX=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_LOGO_M32R_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-CONFIG_USB_SUPPORT=y
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
-# CONFIG_MMC_UNSAFE_RESUME is not set
-
-#
-# MMC/SD Card Drivers
-#
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_BLOCK_BOUNCE=y
-
-#
-# MMC/SD Host Controller Drivers
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
-
-#
-# Userspace I/O
-#
-# CONFIG_UIO is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
-CONFIG_JBD_DEBUG=y
-CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=m
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_REISERFS_FS_XATTR is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_BIND34 is not set
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM is not set
-
-#
-# Profiling support
-#
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_HAS_IOMEM=y
index 41b07854fcc609c5d12c2254e1e09a807f1e9417..15a6f36c06db9c7c84db8d4698339f3f8d9ba413 100644 (file)
@@ -60,9 +60,6 @@ SECTIONS
   . = ALIGN(4096);
   __nosave_end = .;
 
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
index fd0c685a7f11c13de748a5dc2551b4ee73651aa5..c785d07c02cc249ce8e537f13210b9b3edccdb35 100644 (file)
@@ -87,6 +87,7 @@ int main(void)
        DEFINE(TI_TASK, offsetof(struct thread_info, task));
        DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+       DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
        DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 
        return 0;
index 1e7ea6a3e1a146c9a092c33eba6073751f3c0d38..f4782d2dce8f7369fbdaeddd916dc61c57a2afa9 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/segment.h>
 #include <asm/asm-offsets.h>
 #include <asm/entry.h>
+#include <asm/unistd.h>
 
 .text
 
@@ -140,3 +141,11 @@ ENTRY(sys_rt_sigreturn)
        RESTORE_SWITCH_STACK
        rts
 
+ENTRY(ret_from_user_signal)
+       moveq #__NR_sigreturn,%d0
+       trap #0
+
+ENTRY(ret_from_user_rt_signal)
+       move #__NR_rt_sigreturn,%d0
+       trap #0
+
index d6f0200316febaa7f8f1fb76c09c0b96e91b0ad1..03f4fe6a2fc0e20e6e28f233cb8718a4799dd9b6 100644 (file)
@@ -162,7 +162,7 @@ void __init setup_arch(char **cmdline_p)
        printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
 #endif
 #ifdef CONFIG_M5235EVB
-       printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)");
+       printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
 #endif
 
 #ifdef DEBUG
index 70371378db868de2ce8cabf544993e44d4ef8aa2..bbfcae9e52b4b56ff76932e004e58916c8e12d64 100644 (file)
@@ -51,6 +51,8 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
+void ret_from_user_signal(void);
+void ret_from_user_rt_signal(void);
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
 
 /*
@@ -539,10 +541,6 @@ static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
        return err;
 }
 
-static inline void push_cache (unsigned long vaddr)
-{
-}
-
 static inline void *
 get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 {
@@ -586,16 +584,11 @@ static void setup_frame (int sig, struct k_sigaction *ka,
        err |= copy_to_user (&frame->sc, &context, sizeof(context));
 
        /* Set up to return from userspace.  */
-       err |= __put_user(frame->retcode, &frame->pretcode);
-       /* moveq #,d0; trap #0 */
-       err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
-                         (long *)(frame->retcode));
+       err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
 
        if (err)
                goto give_sigsegv;
 
-       push_cache ((unsigned long) &frame->retcode);
-
        /* Set up registers for signal handler */
        wrusp ((unsigned long) frame);
        regs->pc = (unsigned long) ka->sa.sa_handler;
@@ -655,17 +648,11 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
        err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
 
        /* Set up to return from userspace.  */
-       err |= __put_user(frame->retcode, &frame->pretcode);
-       /* moveq #,d0; notb d0; trap #0 */
-       err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
-                         (long *)(frame->retcode + 0));
-       err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
+       err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
 
        if (err)
                goto give_sigsegv;
 
-       push_cache ((unsigned long) &frame->retcode);
-
        /* Set up registers for signal handler */
        wrusp ((unsigned long) frame);
        regs->pc = (unsigned long) ka->sa.sa_handler;
index 437a061d8b94a74745f0e7d55cc96c14d9276e08..ec9aea652e79d0665adcb36fe5e9cd49d9625a51 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <linux/ptrace.h>
+#include <linux/kallsyms.h>
 
 #include <asm/setup.h>
 #include <asm/fpu.h>
@@ -102,56 +103,47 @@ asmlinkage void buserr_c(struct frame *fp)
        force_sig(SIGSEGV, current);
 }
 
-
 int kstack_depth_to_print = 48;
 
-void show_stack(struct task_struct *task, unsigned long *stack)
+static void __show_stack(struct task_struct *task, unsigned long *stack)
 {
        unsigned long *endstack, addr;
-       extern char _start, _etext;
+       unsigned long *last_stack;
        int i;
 
-       if (!stack) {
-               if (task)
-                       stack = (unsigned long *)task->thread.ksp;
-               else
-                       stack = (unsigned long *)&stack;
-       }
+       if (!stack)
+               stack = (unsigned long *)task->thread.ksp;
 
        addr = (unsigned long) stack;
        endstack = (unsigned long *) PAGE_ALIGN(addr);
 
        printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
        for (i = 0; i < kstack_depth_to_print; i++) {
-               if (stack + 1 > endstack)
+               if (stack + 1 + i > endstack)
                        break;
                if (i % 8 == 0)
                        printk("\n" KERN_EMERG "       ");
-               printk(" %08lx", *stack++);
+               printk(" %08lx", *(stack + i));
        }
        printk("\n");
 
-       printk(KERN_EMERG "Call Trace:");
-       i = 0;
-       while (stack + 1 <= endstack) {
-               addr = *stack++;
-               /*
-                * If the address is either in the text segment of the
-                * kernel, or in the region which contains vmalloc'ed
-                * memory, it *may* be the address of a calling
-                * routine; if so, print it so that someone tracing
-                * down the cause of the crash will be able to figure
-                * out the call path that was taken.
-                */
-               if (((addr >= (unsigned long) &_start) &&
-                    (addr <= (unsigned long) &_etext))) {
-                       if (i % 4 == 0)
-                               printk("\n" KERN_EMERG "       ");
-                       printk(" [<%08lx>]", addr);
-                       i++;
-               }
+#ifdef CONFIG_FRAME_POINTER
+       printk(KERN_EMERG "Call Trace:\n");
+
+       last_stack = stack - 1;
+       while (stack <= endstack && stack > last_stack) {
+
+               addr = *(stack + 1);
+               printk(KERN_EMERG " [%08lx] ", addr);
+               print_symbol(KERN_CONT "%s\n", addr);
+
+               last_stack = stack;
+               stack = (unsigned long *)*stack;
        }
        printk("\n");
+#else
+       printk(KERN_EMERG "CONFIG_FRAME_POINTER disabled, no symbolic call trace\n");
+#endif
 }
 
 void bad_super_trap(struct frame *fp)
@@ -298,19 +290,47 @@ asmlinkage void set_esp0(unsigned long ssp)
        current->thread.esp0 = ssp;
 }
 
-
 /*
  * The architecture-independent backtrace generator
  */
 void dump_stack(void)
 {
-       unsigned long stack;
+       /*
+        * We need frame pointers for this little trick, which works as follows:
+        *
+        * +------------+ 0x00
+        * | Next SP    |       -> 0x0c
+        * +------------+ 0x04
+        * | Caller     |
+        * +------------+ 0x08
+        * | Local vars |       -> our stack var
+        * +------------+ 0x0c
+        * | Next SP    |       -> 0x18, that is what we pass to show_stack()
+        * +------------+ 0x10
+        * | Caller     |
+        * +------------+ 0x14
+        * | Local vars |
+        * +------------+ 0x18
+        * | ...        |
+        * +------------+
+        */
 
-       show_stack(current, &stack);
-}
+       unsigned long *stack;
 
+       stack = (unsigned long *)&stack;
+       stack++;
+       __show_stack(current, stack);
+}
 EXPORT_SYMBOL(dump_stack);
 
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+       if (!stack && !task)
+               dump_stack();
+       else
+               __show_stack(task, stack);
+}
+
 #ifdef CONFIG_M68KFPU_EMU
 asmlinkage void fpemu_signal(int signal, int code, void *addr)
 {
index b44edb08e21276f3dce89e8b938c4e6a5252596c..5592e0bf951f555f9efb18c55838215b80cc9db8 100644 (file)
@@ -64,6 +64,7 @@ SECTIONS {
                _stext = . ;
                TEXT_TEXT
                SCHED_TEXT
+               LOCK_TEXT
                *(.text.lock)
 
                . = ALIGN(16);          /* Exception table              */
@@ -73,6 +74,7 @@ SECTIONS {
 
                *(.rodata) *(.rodata.*)
                *(__vermagic)           /* Kernel version magic */
+               *(__markers_strings)
                *(.rodata1)
                *(.rodata.str1.1)
 
@@ -182,6 +184,7 @@ SECTIONS {
                *(COMMON)
                . = ALIGN(4) ;
                _ebss = . ;
+               _end = . ;
        } > BSS
 
 }
index a6692e958f6b93265380bfe7631b57d2fae5fe01..d01a5d2b75579190df5babe0f162a9b1eb947041 100644 (file)
@@ -48,7 +48,7 @@ static struct platform_device *m5206e_devices[] __initdata = {
 
 /***************************************************************************/
 
-static void __init m5206_uart_init_line(int line, int irq)
+static void __init m5206e_uart_init_line(int line, int irq)
 {
        if (line == 0) {
                writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
index 2aca599a1ca714ae2b70ec3d6d89f2ce74dc631f..230bae691a7f4be9060b01397efd7cc20a045ace 100644 (file)
@@ -139,10 +139,6 @@ void __init config_BSP(char *commandp, int size)
        /* Copy command line from FLASH to local buffer... */
        memcpy(commandp, (char *) 0xf0004000, size);
        commandp[size-1] = 0;
-#elif defined(CONFIG_MTD_KeyTechnology)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xffe06000, size);
-       commandp[size-1] = 0;
 #elif defined(CONFIG_CANCam)
        /* Copy command line from FLASH to local buffer... */
        memcpy(commandp, (char *) 0xf0010000, size);
index 036e1b73d94400b8619db75d71e271a5ce2592e3..dfdb5c2ed8e6d35a3ce45b0827c03b61833c2eaf 100644 (file)
 #include <asm/mcfuart.h>
 #include <asm/mcfqspi.h>
 
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
 /***************************************************************************/
 
 void coldfire_reset(void);
+static void coldfire_qspi_cs_control(u8 cs, u8 command);
+
+/***************************************************************************/
+
+#if defined(CONFIG_SPI)
+
+#if defined(CONFIG_WILDFIRE)
+#define SPI_NUM_CHIPSELECTS    0x02
+#define SPI_PAR_VAL            0x07  /* Enable DIN, DOUT, CLK */
+#define SPI_CS_MASK            0x18
+
+#define FLASH_BLOCKSIZE                (1024*64)
+#define FLASH_NUMBLOCKS                16
+#define FLASH_TYPE             "m25p80"
+
+#define M25P80_CS              0
+#define MMC_CS                 1
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition stm25p_partitions[] = {
+       /* sflash */
+       [0] = {
+               .name = "stm25p80",
+               .offset = 0x00000000,
+               .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS,
+               .mask_flags = 0
+       }
+};
+
+#endif
+
+#elif defined(CONFIG_WILDFIREMOD)
+
+#define SPI_NUM_CHIPSELECTS    0x08
+#define SPI_PAR_VAL            0x07  /* Enable DIN, DOUT, CLK */
+#define SPI_CS_MASK            0x78
+
+#define FLASH_BLOCKSIZE                (1024*64)
+#define FLASH_NUMBLOCKS                64
+#define FLASH_TYPE             "m25p32"
+/* Reserve 1M for the kernel parition */
+#define FLASH_KERNEL_SIZE   (1024 * 1024)
+
+#define M25P80_CS              5
+#define MMC_CS                 6
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition stm25p_partitions[] = {
+       /* sflash */
+       [0] = {
+               .name = "kernel",
+               .offset = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE,
+               .size = FLASH_KERNEL_SIZE,
+               .mask_flags = 0
+       },
+       [1] = {
+               .name = "image",
+               .offset = 0x00000000,
+               .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE,
+               .mask_flags = 0
+       },
+       [2] = {
+               .name = "all",
+               .offset = 0x00000000,
+               .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS,
+               .mask_flags = 0
+       }
+};
+#endif
+
+#else
+#define SPI_NUM_CHIPSELECTS    0x04
+#define SPI_PAR_VAL            0x7F  /* Enable DIN, DOUT, CLK, CS0 - CS4 */
+#endif
+
+#ifdef MMC_CS
+static struct coldfire_spi_chip flash_chip_info = {
+       .mode = SPI_MODE_0,
+       .bits_per_word = 16,
+       .del_cs_to_clk = 17,
+       .del_after_trans = 1,
+       .void_write_data = 0
+};
+
+static struct coldfire_spi_chip mmc_chip_info = {
+       .mode = SPI_MODE_0,
+       .bits_per_word = 16,
+       .del_cs_to_clk = 17,
+       .del_after_trans = 1,
+       .void_write_data = 0xFFFF
+};
+#endif
+
+#ifdef M25P80_CS
+static struct flash_platform_data stm25p80_platform_data = {
+       .name = "ST M25P80 SPI Flash chip",
+#ifdef CONFIG_MTD_PARTITIONS
+       .parts = stm25p_partitions,
+       .nr_parts = sizeof(stm25p_partitions) / sizeof(*stm25p_partitions),
+#endif
+       .type = FLASH_TYPE
+};
+#endif
+
+static struct spi_board_info spi_board_info[] __initdata = {
+#ifdef M25P80_CS
+       {
+               .modalias = "m25p80",
+               .max_speed_hz = 16000000,
+               .bus_num = 1,
+               .chip_select = M25P80_CS,
+               .platform_data = &stm25p80_platform_data,
+               .controller_data = &flash_chip_info
+       },
+#endif
+#ifdef MMC_CS
+       {
+               .modalias = "mmc_spi",
+               .max_speed_hz = 16000000,
+               .bus_num = 1,
+               .chip_select = MMC_CS,
+               .controller_data = &mmc_chip_info
+       }
+#endif
+};
+
+static struct coldfire_spi_master coldfire_master_info = {
+       .bus_num = 1,
+       .num_chipselect = SPI_NUM_CHIPSELECTS,
+       .irq_source = MCF5282_QSPI_IRQ_SOURCE,
+       .irq_vector = MCF5282_QSPI_IRQ_VECTOR,
+       .irq_mask = ((0x01 << MCF5282_QSPI_IRQ_SOURCE) | 0x01),
+       .irq_lp = 0x2B,  /* Level 5 and Priority 3 */
+       .par_val = SPI_PAR_VAL,
+       .cs_control = coldfire_qspi_cs_control,
+};
+
+static struct resource coldfire_spi_resources[] = {
+       [0] = {
+               .name = "qspi-par",
+               .start = MCF5282_QSPI_PAR,
+               .end = MCF5282_QSPI_PAR,
+               .flags = IORESOURCE_MEM
+       },
+
+       [1] = {
+               .name = "qspi-module",
+               .start = MCF5282_QSPI_QMR,
+               .end = MCF5282_QSPI_QMR + 0x18,
+               .flags = IORESOURCE_MEM
+       },
+
+       [2] = {
+               .name = "qspi-int-level",
+               .start = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE,
+               .end = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE,
+               .flags = IORESOURCE_MEM
+       },
+
+       [3] = {
+               .name = "qspi-int-mask",
+               .start = MCF5282_INTC0 + MCFINTC_IMRL,
+               .end = MCF5282_INTC0 + MCFINTC_IMRL,
+               .flags = IORESOURCE_MEM
+       }
+};
+
+static struct platform_device coldfire_spi = {
+       .name = "spi_coldfire",
+       .id = -1,
+       .resource = coldfire_spi_resources,
+       .num_resources = ARRAY_SIZE(coldfire_spi_resources),
+       .dev = {
+               .platform_data = &coldfire_master_info,
+       }
+};
+
+static void coldfire_qspi_cs_control(u8 cs, u8 command)
+{
+       u8 cs_bit = ((0x01 << cs) << 3) & SPI_CS_MASK;
+
+#if defined(CONFIG_WILDFIRE)
+       u8 cs_mask = ~(((0x01 << cs) << 3) & SPI_CS_MASK);
+#endif
+#if defined(CONFIG_WILDFIREMOD)
+       u8 cs_mask = (cs << 3) & SPI_CS_MASK;
+#endif
+
+       /*
+        * Don't do anything if the chip select is not
+        * one of the port qs pins.
+        */
+       if (command & QSPI_CS_INIT) {
+#if defined(CONFIG_WILDFIRE)
+               MCF5282_GPIO_DDRQS  |= cs_bit;
+               MCF5282_GPIO_PQSPAR &= ~cs_bit;
+#endif
+
+#if defined(CONFIG_WILDFIREMOD)
+               MCF5282_GPIO_DDRQS  |= SPI_CS_MASK;
+               MCF5282_GPIO_PQSPAR &= ~SPI_CS_MASK;
+#endif
+       }
+
+       if (command & QSPI_CS_ASSERT) {
+               MCF5282_GPIO_PORTQS &= ~SPI_CS_MASK;
+               MCF5282_GPIO_PORTQS |= cs_mask;
+       } else if (command & QSPI_CS_DROP) {
+               MCF5282_GPIO_PORTQS |= SPI_CS_MASK;
+       }
+}
+
+static int __init spi_dev_init(void)
+{
+       int retval;
+
+       retval = platform_device_register(&coldfire_spi);
+       if (retval < 0)
+               return retval;
+
+       if (ARRAY_SIZE(spi_board_info))
+               retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+       return retval;
+}
+
+#endif /* CONFIG_SPI */
 
 /***************************************************************************/
 
@@ -111,10 +342,43 @@ void mcf_autovector(unsigned int vec)
 
 /***************************************************************************/
 
+#ifdef CONFIG_WILDFIRE
+void wildfire_halt(void)
+{
+       writeb(0, 0x30000007);
+       writeb(0x2, 0x30000007);
+}
+#endif
+
+#ifdef CONFIG_WILDFIREMOD
+void wildfiremod_halt(void)
+{
+       printk(KERN_INFO "WildFireMod hibernating...\n");
+
+       /* Set portE.5 to Digital IO */
+       MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2));
+
+       /* Make portE.5 an output */
+       MCF5282_GPIO_DDRE |= (1 << 5);
+
+       /* Now toggle portE.5 from low to high */
+       MCF5282_GPIO_PORTE &= ~(1 << 5);
+       MCF5282_GPIO_PORTE |= (1 << 5);
+
+       printk(KERN_EMERG "Failed to hibernate. Halting!\n");
+}
+#endif
+
 void __init config_BSP(char *commandp, int size)
 {
        mcf_disableall();
-       mach_reset = coldfire_reset;
+
+#ifdef CONFIG_WILDFIRE
+       mach_halt = wildfire_halt;
+#endif
+#ifdef CONFIG_WILDFIREMOD
+       mach_halt = wildfiremod_halt;
+#endif
 }
 
 /***************************************************************************/
index 92dc862fa826edb5432875d585a99d266f2d80ca..11cff6625dcce8ae12b5e6d77abc2b17680edda5 100644 (file)
@@ -124,8 +124,7 @@ void __init config_BSP(char *commandp, int size)
        mcf_setimr(MCFSIM_IMR_MASKALL);
 
 #if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \
-      defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \
-      defined(CONFIG_CLEOPATRA)
+    defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
        /* Copy command line from FLASH to local buffer... */
        memcpy(commandp, (char *) 0xf0004000, size);
        commandp[size-1] = 0;
index 111b66dc737ba5f15e0d2af56b7a85e2db676050..1e3c0dcbd7acec7a1ac9070704d3109bd6d2980e 100644 (file)
@@ -103,9 +103,26 @@ ret_from_signal:
        addql   #4,%sp
 
 ret_from_exception:
+       move    #0x2700,%sr             /* disable intrs */
        btst    #5,%sp@(PT_SR)          /* check if returning to kernel */
        jeq     Luser_return            /* if so, skip resched, signals */
 
+#ifdef CONFIG_PREEMPT
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
+       movel   %d1,%a0
+       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       andl    #_TIF_NEED_RESCHED,%d1
+       jeq     Lkernel_return
+
+       movel   %a0@(TI_PREEMPTCOUNT),%d1
+       cmpl    #0,%d1
+       jne     Lkernel_return
+
+       pea     Lkernel_return
+       jmp     preempt_schedule_irq    /* preempt the kernel */
+#endif
+
 Lkernel_return:
        moveml  %sp@,%d1-%d5/%a0-%a2
        lea     %sp@(32),%sp            /* space for 8 regs */
@@ -140,6 +157,7 @@ Lreturn:
 
 Lwork_to_do:
        movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       move    #0x2000,%sr             /* enable intrs again */
        btst    #TIF_NEED_RESCHED,%d1
        jne     reschedule
 
index 77db3473deabfc20c97acb99d89dbd77c96b9170..9fdd8bcdd21ef1785c90cc40b0579b6acb4dc1a0 100644 (file)
@@ -54,6 +54,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 #include <linux/module.h>
 #include <linux/elfcore.h>
 #include <linux/compat.h>
+#include <linux/math64.h>
 
 #define elf_prstatus elf_prstatus32
 struct elf_prstatus32
@@ -102,8 +103,8 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
         * one divide.
         */
        u64 nsec = (u64)jiffies * TICK_NSEC;
-       long rem;
-       value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+       u32 rem;
+       value->tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
        value->tv_usec = rem / NSEC_PER_USEC;
 }
 
index 08f4cd781ee33cc5ac695fed9705a33e7e507e65..e1333d7319e275a065546490baa8401b87c9bf47 100644 (file)
@@ -56,6 +56,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 #include <linux/module.h>
 #include <linux/elfcore.h>
 #include <linux/compat.h>
+#include <linux/math64.h>
 
 #define elf_prstatus elf_prstatus32
 struct elf_prstatus32
@@ -104,8 +105,8 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
         * one divide.
         */
        u64 nsec = (u64)jiffies * TICK_NSEC;
-       long rem;
-       value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+       u32 rem;
+       value->tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
        value->tv_usec = rem / NSEC_PER_USEC;
 }
 
index 2bde200d5ad0b6aa13371ada255dce2355eae4ca..b39bdba82e029294d1db4ed32df95c53bade32b3 100644 (file)
@@ -27,33 +27,6 @@ struct irix_termios {
        cc_t c_cc[NCCS];
 };
 
-extern void start_tty(struct tty_struct *tty);
-static struct tty_struct *get_tty(int fd)
-{
-       struct file *filp;
-       struct tty_struct *ttyp = NULL;
-
-       rcu_read_lock();
-       filp = fcheck(fd);
-       if(filp && filp->private_data) {
-               ttyp = (struct tty_struct *) filp->private_data;
-
-               if(ttyp->magic != TTY_MAGIC)
-                       ttyp =NULL;
-       }
-       rcu_read_unlock();
-       return ttyp;
-}
-
-static struct tty_struct *get_real_tty(struct tty_struct *tp)
-{
-       if (tp->driver->type == TTY_DRIVER_TYPE_PTY &&
-          tp->driver->subtype == PTY_TYPE_MASTER)
-               return tp->link;
-       else
-               return tp;
-}
-
 asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg)
 {
        struct tty_struct *tp, *rtp;
@@ -146,34 +119,24 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg)
                error = sys_ioctl(fd, TIOCNOTTY, arg);
                break;
 
-       case 0x00007416:
+       case 0x00007416: {
+               pid_t pid;
 #ifdef DEBUG_IOCTLS
                printk("TIOCGSID, %08lx) ", arg);
 #endif
-               tp = get_tty(fd);
-               if(!tp) {
-                       error = -EINVAL;
-                       break;
-               }
-               rtp = get_real_tty(tp);
-#ifdef DEBUG_IOCTLS
-               printk("rtp->session=%d ", rtp->session);
-#endif
-               error = put_user(rtp->session, (unsigned long __user *) arg);
+               old_fs = get_fs(); set_fs(get_ds());
+               error = sys_ioctl(fd, TIOCGSID, (unsigned long)&pid);
+               set_fs(old_fs);
+               if (!error)
+                       error = put_user(pid, (unsigned long __user *) arg);
                break;
-
+       }
        case 0x746e:
                /* TIOCSTART, same effect as hitting ^Q */
 #ifdef DEBUG_IOCTLS
                printk("TIOCSTART, %08lx) ", arg);
 #endif
-               tp = get_tty(fd);
-               if(!tp) {
-                       error = -EINVAL;
-                       break;
-               }
-               rtp = get_real_tty(tp);
-               start_tty(rtp);
+               error = sys_ioctl(fd, TCXONC, TCOON);
                break;
 
        case 0x20006968:
index 998c4efcce88df4acb15485d529badd73a0782eb..ceb62dce1c9c6872966d05e33dacdc96acd5218f 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/sched.h>
 #include <linux/unistd.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/syscalls.h>
 #include <linux/workqueue.h>
index 3b26fbd6bec9ee4978ff6430ce1ef27a55723089..73401e83739a09b4dcefdaecc84451c018607ca5 100644 (file)
@@ -149,7 +149,7 @@ EXPORT_SYMBOL(tb_ticks_per_sec);    /* for cputime_t conversions */
 u64 tb_to_xs;
 unsigned tb_to_us;
 
-#define TICKLEN_SCALE  TICK_LENGTH_SHIFT
+#define TICKLEN_SCALE  NTP_SCALE_SHIFT
 u64 last_tick_len;     /* units are ns / 2^TICKLEN_SCALE */
 u64 ticklen_to_xs;     /* 0.64 fraction */
 
@@ -1007,8 +1007,6 @@ void __init time_init(void)
        vdso_data->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
        vdso_data->tb_to_xs = tb_to_xs;
 
-       time_freq = 0;
-
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
        /* Register the clocksource, if we're not running on iSeries */
index b962c3ab470cbe01f2f5a5d6e510866bd8a60e5a..af116aadba105674617cb97e514996797501dc5c 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/elf.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/module.h>
index f70e3e3a9fa78ca0649adccf695ad8df40ade0e3..c3f880902d66555afd6e079292f23ec009126f34 100644 (file)
@@ -25,6 +25,18 @@ config X86
        select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
        select HAVE_ARCH_KGDB if !X86_VOYAGER
 
+config DEFCONFIG_LIST
+       string
+       depends on X86_32
+       option defconfig_list
+       default "arch/x86/configs/i386_defconfig"
+
+config DEFCONFIG_LIST
+       string
+       depends on X86_64
+       option defconfig_list
+       default "arch/x86/configs/x86_64_defconfig"
+
 
 config GENERIC_LOCKBREAK
        def_bool n
@@ -180,7 +192,7 @@ config X86_HT
 
 config X86_BIOS_REBOOT
        bool
-       depends on X86_32 && !(X86_VISWS || X86_VOYAGER)
+       depends on !X86_VISWS && !X86_VOYAGER
        default y
 
 config X86_TRAMPOLINE
@@ -1161,7 +1173,7 @@ source kernel/Kconfig.hz
 
 config KEXEC
        bool "kexec system call"
-       depends on X86_64 || X86_BIOS_REBOOT
+       depends on X86_BIOS_REBOOT
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 7ef18b01f0bca49c4da9ed1ed78b330ab1506da4..2ad6301849a1ba68ec78c9ea3c5f39232484c645 100644 (file)
@@ -278,11 +278,6 @@ config GENERIC_CPU
 
 endchoice
 
-config X86_CPU
-       def_bool y
-       select GENERIC_FIND_FIRST_BIT
-       select GENERIC_FIND_NEXT_BIT
-
 config X86_GENERIC
        bool "Generic x86 support"
        depends on X86_32
@@ -297,6 +292,11 @@ config X86_GENERIC
 
 endif
 
+config X86_CPU
+       def_bool y
+       select GENERIC_FIND_FIRST_BIT
+       select GENERIC_FIND_NEXT_BIT
+
 #
 # Define implied options from the CPU selection here
 config X86_L1_CACHE_BYTES
index 5b1979a45a1ea07f6ffc8d6b563fc1ddcb64dae3..ac1e31ba4795cb0f067a280826da257432f93f33 100644 (file)
@@ -118,7 +118,6 @@ config DEBUG_NX_TEST
 config 4KSTACKS
        bool "Use 4Kb for kernel stacks instead of 8Kb"
        depends on X86_32
-       default y
        help
          If you say Y here the kernel will use a 4Kb stacksize for the
          kernel stack attached to each process/thread. This facilitates
@@ -256,11 +255,9 @@ config CPA_DEBUG
        help
          Do change_page_attr() self-tests every 30 seconds.
 
-endmenu
-
 config OPTIMIZE_INLINING
        bool "Allow gcc to uninline functions marked 'inline'"
-       default y
+       depends on BROKEN
        help
          This option determines if the kernel forces gcc to inline the functions
          developers have marked 'inline'. Doing so takes away freedom from gcc to
@@ -270,3 +267,6 @@ config OPTIMIZE_INLINING
          this algorithm is so good that allowing gcc4 to make the decision can
          become the default in the future, until then this option is there to
          test gcc for this.
+
+endmenu
+
index 30d54ed27e558cb1d3725f38c411e820b7fe5073..bbdacb398d48e05a05c17f23af0d2b650751d912 100644 (file)
@@ -40,7 +40,6 @@ obj-$(CONFIG_STACKTRACE)      += stacktrace.o
 obj-y                          += cpu/
 obj-y                          += acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)  += reboot.o
-obj-$(CONFIG_X86_64)           += reboot.o
 obj-$(CONFIG_MCA)              += mca_32.o
 obj-$(CONFIG_X86_MSR)          += msr.o
 obj-$(CONFIG_X86_CPUID)                += cpuid.o
index 021624c835832d81f00f1ed6ef5d5437e9303813..cbaaf69bedb29c92055e2272a12efba7f49f9ee1 100644 (file)
@@ -83,7 +83,7 @@ unsigned int read_apic_id(void)
 {
        unsigned int id;
 
-       WARN_ON(preemptible());
+       WARN_ON(preemptible() && num_online_cpus() > 1);
        id = apic_read(APIC_ID);
        if (uv_system_type >= UV_X2APIC)
                id  |= __get_cpu_var(x2apic_extra_bits);
index 90f038af3adc326725cbdec61825e1b31f340ebb..b2cc73768a9daaa5f6e568bd4977f6fea7889d87 100644 (file)
@@ -656,15 +656,16 @@ int_msg:
        .asciz "Unknown interrupt or fault at EIP %p %p %p\n"
 
 fault_msg:
-       .asciz                                                          \
-/* fault info: */      "BUG: Int %d: CR2 %p\n"                         \
-/* pusha regs: */      "     EDI %p  ESI %p  EBP %p  ESP %p\n"         \
-                       "     EBX %p  EDX %p  ECX %p  EAX %p\n"         \
-/* fault frame: */     "     err %p  EIP %p   CS %p  flg %p\n"         \
-                                                                       \
-                       "Stack: %p %p %p %p %p %p %p %p\n"              \
-                       "       %p %p %p %p %p %p %p %p\n"              \
-                       "       %p %p %p %p %p %p %p %p\n"
+/* fault info: */
+       .ascii "BUG: Int %d: CR2 %p\n"
+/* pusha regs: */
+       .ascii "     EDI %p  ESI %p  EBP %p  ESP %p\n"
+       .ascii "     EBX %p  EDX %p  ECX %p  EAX %p\n"
+/* fault frame: */
+       .ascii "     err %p  EIP %p   CS %p  flg %p\n"
+       .ascii "Stack: %p %p %p %p %p %p %p %p\n"
+       .ascii "       %p %p %p %p %p %p %p %p\n"
+       .asciz "       %p %p %p %p %p %p %p %p\n"
 
 #include "../../x86/xen/xen-head.S"
 
index 9007f9ea64eed80e9537be44d391fe55d6f7f749..9b5cfcdfc426cc194365020c061c6c0b46e54083 100644 (file)
@@ -137,9 +137,10 @@ static void hpet_reserve_platform_timers(unsigned long id)
        hd.hd_irq[0] = HPET_LEGACY_8254;
        hd.hd_irq[1] = HPET_LEGACY_RTC;
 
-       for (i = 2; i < nrtimers; timer++, i++)
-               hd.hd_irq[i] = (timer->hpet_config & Tn_INT_ROUTE_CNF_MASK) >>
+       for (i = 2; i < nrtimers; timer++, i++) {
+               hd.hd_irq[i] = (readl(&timer->hpet_config) & Tn_INT_ROUTE_CNF_MASK) >>
                        Tn_INT_ROUTE_CNF_SHIFT;
+       }
 
        hpet_alloc(&hd);
 
index 388b113a7d88ffbc0efaf52c348412af9e439a8c..0c37f16b69502e1fe31f4e94c80775dc1fd22060 100644 (file)
@@ -14,7 +14,7 @@ EXPORT_SYMBOL(forbid_dac);
 const struct dma_mapping_ops *dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
-int iommu_sac_force __read_mostly = 0;
+static int iommu_sac_force __read_mostly;
 
 #ifdef CONFIG_IOMMU_DEBUG
 int panic_on_overflow __read_mostly = 1;
index a4a838306b2cc69f2856f1b8244b6045c86165c9..07c6d42ab5ff326203f417c1b8ccbc9ae1fc5dac 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/desc.h>
 #include <asm/hpet.h>
 #include <asm/pgtable.h>
+#include <asm/proto.h>
 #include <asm/reboot_fixups.h>
 #include <asm/reboot.h>
 
index 361e31611276d03018f4b16d275a04b5e478f2cf..4c943eabacc39ecf39d9e4a21ecae64ea3bc8d6a 100644 (file)
@@ -35,7 +35,7 @@
 #include "i8254.h"
 
 #ifndef CONFIG_X86_64
-#define mod_64(x, y) ((x) - (y) * div64_64(x, y))
+#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
 #else
 #define mod_64(x, y) ((x) % (y))
 #endif
@@ -60,8 +60,8 @@ static u64 muldiv64(u64 a, u32 b, u32 c)
        rl = (u64)u.l.low * (u64)b;
        rh = (u64)u.l.high * (u64)b;
        rh += (rl >> 32);
-       res.l.high = div64_64(rh, c);
-       res.l.low = div64_64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c);
+       res.l.high = div64_u64(rh, c);
+       res.l.low = div64_u64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c);
        return res.ll;
 }
 
index 57ac4e4c556a5a3ca5bc79a8acbd1e35f3f33d9d..36809d79788bedffcd8332609c7313175aa09e3a 100644 (file)
 #include <linux/hrtimer.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/math64.h>
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/page.h>
 #include <asm/current.h>
 #include <asm/apicdef.h>
 #include <asm/atomic.h>
-#include <asm/div64.h>
 #include "irq.h"
 
 #define PRId64 "d"
@@ -526,8 +526,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
        } else
                passed = ktime_sub(now, apic->timer.last_update);
 
-       counter_passed = div64_64(ktime_to_ns(passed),
-                                 (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+       counter_passed = div64_u64(ktime_to_ns(passed),
+                                  (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
 
        if (counter_passed > tmcct) {
                if (unlikely(!apic_lvtt_period(apic))) {
index ecab9fff0fd17579b43d550f8bae2e5eea98f22b..2ad598c104af77d398e59a1e6d4edc04ed91ea53 100644 (file)
@@ -877,7 +877,7 @@ void __init voyager_cat_init(void)
                        request_resource(&iomem_resource, res);
                }
 
-               qic_addr = (unsigned long)ioremap(qic_addr, 0x400);
+               qic_addr = (unsigned long)ioremap_cache(qic_addr, 0x400);
 
                for (j = 0; j < 4; j++) {
                        __u8 cpu;
index 9cf33d3ee5bc7ee0d10fbc4b0ce9c9fc04697ee8..165c871ba9af0211e0c939e0bc2212750d4bf39f 100644 (file)
@@ -155,4 +155,3 @@ EXPORT_SYMBOL(kmap);
 EXPORT_SYMBOL(kunmap);
 EXPORT_SYMBOL(kmap_atomic);
 EXPORT_SYMBOL(kunmap_atomic);
-EXPORT_SYMBOL(kmap_atomic_to_page);
index 804de18abcc2b47e7cf4e880a9b23ee159091061..71bb3159031afba912c9a60cad9f4510a3074ff3 100644 (file)
@@ -149,7 +149,8 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
         * Don't allow anybody to remap normal RAM that we're using..
         */
        for (pfn = phys_addr >> PAGE_SHIFT;
-                               (pfn << PAGE_SHIFT) < last_addr; pfn++) {
+                               (pfn << PAGE_SHIFT) < (last_addr & PAGE_MASK);
+                               pfn++) {
 
                int is_ram = page_is_ram(pfn);
 
@@ -176,11 +177,11 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
                /*
                 * Do not fallback to certain memory types with certain
                 * requested type:
-                * - request is uncached, return cannot be write-back
-                * - request is uncached, return cannot be write-combine
+                * - request is uc-, return cannot be write-back
+                * - request is uc-, return cannot be write-combine
                 * - request is write-combine, return cannot be write-back
                 */
-               if ((prot_val == _PAGE_CACHE_UC &&
+               if ((prot_val == _PAGE_CACHE_UC_MINUS &&
                     (new_prot_val == _PAGE_CACHE_WB ||
                      new_prot_val == _PAGE_CACHE_WC)) ||
                    (prot_val == _PAGE_CACHE_WC &&
@@ -201,6 +202,9 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        default:
                prot = PAGE_KERNEL_NOCACHE;
                break;
+       case _PAGE_CACHE_UC_MINUS:
+               prot = PAGE_KERNEL_UC_MINUS;
+               break;
        case _PAGE_CACHE_WC:
                prot = PAGE_KERNEL_WC;
                break;
@@ -255,7 +259,16 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
  */
 void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
 {
-       return __ioremap_caller(phys_addr, size, _PAGE_CACHE_UC,
+       /*
+        * Ideally, this should be:
+        *      pat_wc_enabled ? _PAGE_CACHE_UC : _PAGE_CACHE_UC_MINUS;
+        *
+        * Till we fix all X drivers to use ioremap_wc(), we will use
+        * UC MINUS.
+        */
+       unsigned long val = _PAGE_CACHE_UC_MINUS;
+
+       return __ioremap_caller(phys_addr, size, val,
                                __builtin_return_address(0));
 }
 EXPORT_SYMBOL(ioremap_nocache);
index bd5e05c654dccfb33d368718e4b7acdbdd16d5d0..60bcb5b6a37ef0130fb08da8ef38db58fd37910a 100644 (file)
@@ -777,14 +777,20 @@ static inline int change_page_attr_clear(unsigned long addr, int numpages,
 
 int _set_memory_uc(unsigned long addr, int numpages)
 {
+       /*
+        * for now UC MINUS. see comments in ioremap_nocache()
+        */
        return change_page_attr_set(addr, numpages,
-                                   __pgprot(_PAGE_CACHE_UC));
+                                   __pgprot(_PAGE_CACHE_UC_MINUS));
 }
 
 int set_memory_uc(unsigned long addr, int numpages)
 {
+       /*
+        * for now UC MINUS. see comments in ioremap_nocache()
+        */
        if (reserve_memtype(addr, addr + numpages * PAGE_SIZE,
-                           _PAGE_CACHE_UC, NULL))
+                           _PAGE_CACHE_UC_MINUS, NULL))
                return -EINVAL;
 
        return _set_memory_uc(addr, numpages);
index 2a1516efb5426dcb79f6b77283e2aeb813811711..7fa519868d7091d4dd0b64fbb880c68517428f99 100644 (file)
@@ -9,8 +9,8 @@ pci-y                           := fixup.o
 pci-$(CONFIG_ACPI)             += acpi.o
 pci-y                          += legacy.o irq.o
 
-pci-$(CONFIG_X86_VISWS)                := visws.o fixup.o
-pci-$(CONFIG_X86_NUMAQ)                := numa.o irq.o
+pci-$(CONFIG_X86_VISWS)                += visws.o fixup.o
+pci-$(CONFIG_X86_NUMAQ)                += numa.o irq.o
 pci-$(CONFIG_NUMA)             += mp_bus_to_node.o
 
 obj-y                          += $(pci-y) common.o early.o
index 94f6c73a53d0aae6ac048668ea6b06a0a1f370d0..8af0f0bae2af45f0baca08051056946235db7d1e 100644 (file)
@@ -301,6 +301,13 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        prot = pgprot_val(vma->vm_page_prot);
        if (pat_wc_enabled && write_combine)
                prot |= _PAGE_CACHE_WC;
+       else if (pat_wc_enabled)
+               /*
+                * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
+                * To avoid attribute conflicts, request UC MINUS here
+                * aswell.
+                */
+               prot |= _PAGE_CACHE_UC_MINUS;
        else if (boot_cpu_data.x86 > 3)
                prot |= _PAGE_CACHE_UC;
 
@@ -319,9 +326,8 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                 * - request is uncached, return cannot be write-combine
                 * - request is write-combine, return cannot be write-back
                 */
-               if ((flags == _PAGE_CACHE_UC &&
-                    (new_flags == _PAGE_CACHE_WB ||
-                     new_flags == _PAGE_CACHE_WC)) ||
+               if ((flags == _PAGE_CACHE_UC_MINUS &&
+                    (new_flags == _PAGE_CACHE_WB)) ||
                    (flags == _PAGE_CACHE_WC &&
                     new_flags == _PAGE_CACHE_WB)) {
                        free_memtype(addr, addr+len);
index e2af8eee80e35b2915c461b469be6c0a4eb0f804..4dceeb1fc5e0f229305c983d39c8cf6497b5a409 100644 (file)
@@ -303,8 +303,6 @@ int __init sysenter_setup(void)
 
 #ifdef CONFIG_X86_32
        gate_vma_init();
-
-       printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
 #endif
 
        if (!vdso32_sysenter()) {
index 66e55288178c0840ba44ff0a859fc72c817baf89..a09ead19f9c5702a1ad76d709c54969176fe9e94 100644 (file)
@@ -26,8 +26,7 @@ int blk_queue_ordered(struct request_queue *q, unsigned ordered,
 {
        if (ordered & (QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH) &&
            prepare_flush_fn == NULL) {
-               printk(KERN_ERR "%s: prepare_flush_fn required\n",
-                                                               __FUNCTION__);
+               printk(KERN_ERR "%s: prepare_flush_fn required\n", __func__);
                return -EINVAL;
        }
 
index 5d09f8c56024011588ec1b89e90bff2033a150ca..b754a4a2f9bd26e2e3aaed11fb6fa3a9c3d67d0b 100644 (file)
@@ -136,7 +136,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
 
                if (unlikely(nbytes > bio->bi_size)) {
                        printk(KERN_ERR "%s: want %u bytes done, %u left\n",
-                              __FUNCTION__, nbytes, bio->bi_size);
+                              __func__, nbytes, bio->bi_size);
                        nbytes = bio->bi_size;
                }
 
@@ -1566,8 +1566,7 @@ static int __end_that_request_first(struct request *req, int error,
                        if (unlikely(bio->bi_idx >= bio->bi_vcnt)) {
                                blk_dump_rq_flags(req, "__end_that");
                                printk(KERN_ERR "%s: bio idx %d >= vcnt %d\n",
-                                               __FUNCTION__, bio->bi_idx,
-                                               bio->bi_vcnt);
+                                      __func__, bio->bi_idx, bio->bi_vcnt);
                                break;
                        }
 
index 6089384ab06499becc951478d06dda2e22aa7e00..bb93d4c32775abdc2fdba16c3bc208fb20045f47 100644 (file)
@@ -168,8 +168,8 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors)
 {
        if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
                max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
-               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
-                                                       max_sectors);
+               printk(KERN_INFO "%s: set to minimum %d\n",
+                      __func__, max_sectors);
        }
 
        if (BLK_DEF_MAX_SECTORS > max_sectors)
@@ -196,8 +196,8 @@ void blk_queue_max_phys_segments(struct request_queue *q,
 {
        if (!max_segments) {
                max_segments = 1;
-               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
-                                                       max_segments);
+               printk(KERN_INFO "%s: set to minimum %d\n",
+                      __func__, max_segments);
        }
 
        q->max_phys_segments = max_segments;
@@ -220,8 +220,8 @@ void blk_queue_max_hw_segments(struct request_queue *q,
 {
        if (!max_segments) {
                max_segments = 1;
-               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
-                                                       max_segments);
+               printk(KERN_INFO "%s: set to minimum %d\n",
+                      __func__, max_segments);
        }
 
        q->max_hw_segments = max_segments;
@@ -241,8 +241,8 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size)
 {
        if (max_size < PAGE_CACHE_SIZE) {
                max_size = PAGE_CACHE_SIZE;
-               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
-                                                       max_size);
+               printk(KERN_INFO "%s: set to minimum %d\n",
+                      __func__, max_size);
        }
 
        q->max_segment_size = max_size;
@@ -357,8 +357,8 @@ void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask)
 {
        if (mask < PAGE_CACHE_SIZE - 1) {
                mask = PAGE_CACHE_SIZE - 1;
-               printk(KERN_INFO "%s: set to minimum %lx\n", __FUNCTION__,
-                                                       mask);
+               printk(KERN_INFO "%s: set to minimum %lx\n",
+                      __func__, mask);
        }
 
        q->seg_boundary_mask = mask;
index e176ddbe599e23796c004e3d0354cbc4c6b337cf..de64e04299771f08eebb391616d63b72c2fca64a 100644 (file)
@@ -112,7 +112,7 @@ init_tag_map(struct request_queue *q, struct blk_queue_tag *tags, int depth)
        if (q && depth > q->nr_requests * 2) {
                depth = q->nr_requests * 2;
                printk(KERN_ERR "%s: adjusted depth to %d\n",
-                               __FUNCTION__, depth);
+                      __func__, depth);
        }
 
        tag_index = kzalloc(depth * sizeof(struct request *), GFP_ATOMIC);
@@ -296,13 +296,13 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq)
 
        if (unlikely(bqt->tag_index[tag] == NULL))
                printk(KERN_ERR "%s: tag %d is missing\n",
-                      __FUNCTION__, tag);
+                      __func__, tag);
 
        bqt->tag_index[tag] = NULL;
 
        if (unlikely(!test_bit(tag, bqt->tag_map))) {
                printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n",
-                      __FUNCTION__, tag);
+                      __func__, tag);
                return;
        }
        /*
@@ -340,7 +340,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
        if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
                printk(KERN_ERR
                       "%s: request %p for device [%s] already tagged %d",
-                      __FUNCTION__, rq,
+                      __func__, rq,
                       rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->tag);
                BUG();
        }
index 23ea4fd1a66d9464b0b3af5dd53f997852f65c1a..f0b7cd3432160203ea6c650088ccfcd4acf2a3f6 100644 (file)
@@ -57,7 +57,7 @@ enum {
 #undef BSG_DEBUG
 
 #ifdef BSG_DEBUG
-#define dprintk(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ##args)
+#define dprintk(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ##args)
 #else
 #define dprintk(fmt, args...)
 #endif
@@ -174,7 +174,11 @@ unlock:
 static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
                                struct sg_io_v4 *hdr, int has_write_perm)
 {
-       memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
+       if (hdr->request_len > BLK_MAX_CDB) {
+               rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
+               if (!rq->cmd)
+                       return -ENOMEM;
+       }
 
        if (copy_from_user(rq->cmd, (void *)(unsigned long)hdr->request,
                           hdr->request_len))
@@ -211,8 +215,6 @@ bsg_validate_sgv4_hdr(struct request_queue *q, struct sg_io_v4 *hdr, int *rw)
 
        if (hdr->guard != 'Q')
                return -EINVAL;
-       if (hdr->request_len > BLK_MAX_CDB)
-               return -EINVAL;
        if (hdr->dout_xfer_len > (q->max_sectors << 9) ||
            hdr->din_xfer_len > (q->max_sectors << 9))
                return -EIO;
@@ -302,6 +304,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr)
        }
        return rq;
 out:
+       if (rq->cmd != rq->__cmd)
+               kfree(rq->cmd);
        blk_put_request(rq);
        if (next_rq) {
                blk_rq_unmap_user(next_rq->bio);
@@ -455,6 +459,8 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
                ret = rq->errors;
 
        blk_rq_unmap_user(bio);
+       if (rq->cmd != rq->__cmd)
+               kfree(rq->cmd);
        blk_put_request(rq);
 
        return ret;
index ac5310ef8270984e32799e0524917abf4246853a..980f8ae147b4c396b15886be25bd9b2342322472 100644 (file)
@@ -650,7 +650,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
 
        default:
                printk(KERN_ERR "%s: bad insertion point %d\n",
-                      __FUNCTION__, where);
+                      __func__, where);
                BUG();
        }
 
@@ -808,8 +808,7 @@ struct request *elv_next_request(struct request_queue *q)
                        rq->cmd_flags |= REQ_QUIET;
                        end_queued_request(rq, 0);
                } else {
-                       printk(KERN_ERR "%s: bad return=%d\n", __FUNCTION__,
-                                                               ret);
+                       printk(KERN_ERR "%s: bad return=%d\n", __func__, ret);
                        break;
                }
        }
index ffa3720e6ca05de7830a466664327deed289aa12..78199c08ec92fc7c23549ef41c7d5b0862cfb938 100644 (file)
 #include <scsi/scsi_cmnd.h>
 
 /* Command group 3 is reserved and should never be used.  */
-const unsigned char scsi_command_size[8] =
+const unsigned char scsi_command_size_tbl[8] =
 {
        6, 10, 10, 12,
        16, 12, 10, 10
 };
-
-EXPORT_SYMBOL(scsi_command_size);
+EXPORT_SYMBOL(scsi_command_size_tbl);
 
 #include <scsi/sg.h>
 
index ed8ac5a6fa5ff0bc22fa67fc193a1b0629d4a063..4b226768752abed604033f708d093f0b04aee41b 100644 (file)
@@ -217,9 +217,10 @@ static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,
                                           int err)
 {
        if (!err) {
-               struct aead_givcrypt_request *greq = req->data;
+               struct aead_request *areq = req->data;
+               struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
 
-               err = crypto_authenc_genicv(&greq->areq, greq->giv, 0);
+               err = crypto_authenc_genicv(areq, greq->giv, 0);
        }
 
        aead_request_complete(req->data, err);
index 250425263e00e59fad2b5a11436ce5a02b9dbe41..b150de562057f59bd85a69f0bb4e3267589c6bff 100644 (file)
@@ -190,8 +190,10 @@ static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
        int err;
 
        inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
-       if (IS_ERR(inst))
+       if (!inst) {
+               inst = ERR_PTR(-ENOMEM);
                goto out;
+       }
 
        err = -ENAMETOOLONG;
        if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
index b14f14e314b6cf3ada4bc0694aa9f5f364ab73e7..881d30910434831f528f5be244ab502bd984d0b6 100644 (file)
@@ -136,7 +136,8 @@ static int eseqiv_givencrypt(struct skcipher_givcrypt_request *req)
        }
 
        ablkcipher_request_set_crypt(subreq, reqctx->src, dst,
-                                    req->creq.nbytes, req->creq.info);
+                                    req->creq.nbytes + ivsize,
+                                    req->creq.info);
 
        memcpy(req->creq.info, ctx->salt, ivsize);
 
index f7eb12e55602ecc1f0dc8c9b93ff2e01d3e8a824..5e5dda3a3027abfa1554a9b44c5ae636cd1e7133 100644 (file)
@@ -1070,7 +1070,7 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
        device_dir->owner = THIS_MODULE;
 
        /* 'info' [R] */
-       entry = proc_create_data("info", S_IRUGO, acpi_device_dir(device),
+       entry = proc_create_data("info", S_IRUGO, device_dir,
                        &acpi_video_device_info_fops, acpi_driver_data(device));
        if (!entry)
                goto err_remove_dir;
@@ -1078,7 +1078,7 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
        /* 'state' [R/W] */
        acpi_video_device_state_fops.write = acpi_video_device_write_state;
        entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR,
-                                acpi_device_dir(device),
+                                device_dir,
                                 &acpi_video_device_state_fops,
                                 acpi_driver_data(device));
        if (!entry)
@@ -1088,19 +1088,21 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
        acpi_video_device_brightness_fops.write =
                acpi_video_device_write_brightness;
        entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR,
-                                acpi_device_dir(device),
+                                device_dir,
                                 &acpi_video_device_brightness_fops,
                                 acpi_driver_data(device));
        if (!entry)
                goto err_remove_state;
 
        /* 'EDID' [R] */
-       entry = proc_create_data("EDID", S_IRUGO, acpi_device_dir(device),
+       entry = proc_create_data("EDID", S_IRUGO, device_dir,
                                 &acpi_video_device_EDID_fops,
                                 acpi_driver_data(device));
        if (!entry)
                goto err_remove_brightness;
 
+       acpi_device_dir(device) = device_dir;
+
        return 0;
 
  err_remove_brightness:
@@ -1346,21 +1348,21 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
        device_dir->owner = THIS_MODULE;
 
        /* 'info' [R] */
-       entry = proc_create_data("info", S_IRUGO, acpi_device_dir(device),
+       entry = proc_create_data("info", S_IRUGO, device_dir,
                                 &acpi_video_bus_info_fops,
                                 acpi_driver_data(device));
        if (!entry)
                goto err_remove_dir;
 
        /* 'ROM' [R] */
-       entry = proc_create_data("ROM", S_IRUGO, acpi_device_dir(device),
+       entry = proc_create_data("ROM", S_IRUGO, device_dir,
                                 &acpi_video_bus_ROM_fops,
                                 acpi_driver_data(device));
        if (!entry)
                goto err_remove_info;
 
        /* 'POST_info' [R] */
-       entry = proc_create_data("POST_info", S_IRUGO, acpi_device_dir(device),
+       entry = proc_create_data("POST_info", S_IRUGO, device_dir,
                                 &acpi_video_bus_POST_info_fops,
                                 acpi_driver_data(device));
        if (!entry)
@@ -1369,7 +1371,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
        /* 'POST' [R/W] */
        acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
        entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR,
-                                acpi_device_dir(device),
+                                device_dir,
                                 &acpi_video_bus_POST_fops,
                                 acpi_driver_data(device));
        if (!entry)
@@ -1378,7 +1380,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
        /* 'DOS' [R/W] */
        acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
        entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR,
-                                acpi_device_dir(device),
+                                device_dir,
                                 &acpi_video_bus_DOS_fops,
                                 acpi_driver_data(device));
        if (!entry)
index c0444146c09a880a51e1b514e9fe8710119a2f67..2c9ae43e221933607e81f32b26c40f7156447dc5 100644 (file)
@@ -64,17 +64,6 @@ extern void sysdev_shutdown(void);
 extern int sysdev_suspend(pm_message_t state);
 extern int sysdev_resume(void);
 
-static inline struct class_device *to_class_dev(struct kobject *obj)
-{
-       return container_of(obj, struct class_device, kobj);
-}
-
-static inline
-struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
-{
-       return container_of(_attr, struct class_device_attribute, attr);
-}
-
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
index b4901799308b00d2755e1536e477976a8302ff08..0ef00e8d4153879513bfa2823a7fad0e25e4f6b7 100644 (file)
@@ -179,27 +179,13 @@ static void class_create_release(struct class *cls)
        kfree(cls);
 }
 
-static void class_device_create_release(struct class_device *class_dev)
-{
-       pr_debug("%s called for %s\n", __func__, class_dev->class_id);
-       kfree(class_dev);
-}
-
-/* needed to allow these devices to have parent class devices */
-static int class_device_create_uevent(struct class_device *class_dev,
-                                     struct kobj_uevent_env *env)
-{
-       pr_debug("%s called for %s\n", __func__, class_dev->class_id);
-       return 0;
-}
-
 /**
  * class_create - create a struct class structure
  * @owner: pointer to the module that is to "own" this struct class
  * @name: pointer to a string for the name of this class.
  *
  * This is used to create a struct class pointer that can then be used
- * in calls to class_device_create().
+ * in calls to device_create().
  *
  * Note, the pointer created here is to be destroyed when finished by
  * making a call to class_destroy().
@@ -218,7 +204,6 @@ struct class *class_create(struct module *owner, const char *name)
        cls->name = name;
        cls->owner = owner;
        cls->class_release = class_create_release;
-       cls->release = class_device_create_release;
 
        retval = class_register(cls);
        if (retval)
@@ -246,113 +231,6 @@ void class_destroy(struct class *cls)
        class_unregister(cls);
 }
 
-/* Class Device Stuff */
-
-int class_device_create_file(struct class_device *class_dev,
-                            const struct class_device_attribute *attr)
-{
-       int error = -EINVAL;
-       if (class_dev)
-               error = sysfs_create_file(&class_dev->kobj, &attr->attr);
-       return error;
-}
-
-void class_device_remove_file(struct class_device *class_dev,
-                             const struct class_device_attribute *attr)
-{
-       if (class_dev)
-               sysfs_remove_file(&class_dev->kobj, &attr->attr);
-}
-
-int class_device_create_bin_file(struct class_device *class_dev,
-                                struct bin_attribute *attr)
-{
-       int error = -EINVAL;
-       if (class_dev)
-               error = sysfs_create_bin_file(&class_dev->kobj, attr);
-       return error;
-}
-
-void class_device_remove_bin_file(struct class_device *class_dev,
-                                 struct bin_attribute *attr)
-{
-       if (class_dev)
-               sysfs_remove_bin_file(&class_dev->kobj, attr);
-}
-
-static ssize_t class_device_attr_show(struct kobject *kobj,
-                                     struct attribute *attr, char *buf)
-{
-       struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
-       struct class_device *cd = to_class_dev(kobj);
-       ssize_t ret = 0;
-
-       if (class_dev_attr->show)
-               ret = class_dev_attr->show(cd, buf);
-       return ret;
-}
-
-static ssize_t class_device_attr_store(struct kobject *kobj,
-                                      struct attribute *attr,
-                                      const char *buf, size_t count)
-{
-       struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
-       struct class_device *cd = to_class_dev(kobj);
-       ssize_t ret = 0;
-
-       if (class_dev_attr->store)
-               ret = class_dev_attr->store(cd, buf, count);
-       return ret;
-}
-
-static struct sysfs_ops class_dev_sysfs_ops = {
-       .show   = class_device_attr_show,
-       .store  = class_device_attr_store,
-};
-
-static void class_dev_release(struct kobject *kobj)
-{
-       struct class_device *cd = to_class_dev(kobj);
-       struct class *cls = cd->class;
-
-       pr_debug("device class '%s': release.\n", cd->class_id);
-
-       if (cd->release)
-               cd->release(cd);
-       else if (cls->release)
-               cls->release(cd);
-       else {
-               printk(KERN_ERR "Class Device '%s' does not have a release() "
-                       "function, it is broken and must be fixed.\n",
-                       cd->class_id);
-               WARN_ON(1);
-       }
-}
-
-static struct kobj_type class_device_ktype = {
-       .sysfs_ops      = &class_dev_sysfs_ops,
-       .release        = class_dev_release,
-};
-
-static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
-{
-       struct kobj_type *ktype = get_ktype(kobj);
-
-       if (ktype == &class_device_ktype) {
-               struct class_device *class_dev = to_class_dev(kobj);
-               if (class_dev->class)
-                       return 1;
-       }
-       return 0;
-}
-
-static const char *class_uevent_name(struct kset *kset, struct kobject *kobj)
-{
-       struct class_device *class_dev = to_class_dev(kobj);
-
-       return class_dev->class->name;
-}
-
 #ifdef CONFIG_SYSFS_DEPRECATED
 char *make_class_name(const char *name, struct kobject *kobj)
 {
@@ -370,445 +248,8 @@ char *make_class_name(const char *name, struct kobject *kobj)
        strcat(class_name, kobject_name(kobj));
        return class_name;
 }
-
-static int make_deprecated_class_device_links(struct class_device *class_dev)
-{
-       char *class_name;
-       int error;
-
-       if (!class_dev->dev)
-               return 0;
-
-       class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
-       if (class_name)
-               error = sysfs_create_link(&class_dev->dev->kobj,
-                                         &class_dev->kobj, class_name);
-       else
-               error = -ENOMEM;
-       kfree(class_name);
-       return error;
-}
-
-static void remove_deprecated_class_device_links(struct class_device *class_dev)
-{
-       char *class_name;
-
-       if (!class_dev->dev)
-               return;
-
-       class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
-       if (class_name)
-               sysfs_remove_link(&class_dev->dev->kobj, class_name);
-       kfree(class_name);
-}
-#else
-static inline int make_deprecated_class_device_links(struct class_device *cd)
-{ return 0; }
-static void remove_deprecated_class_device_links(struct class_device *cd)
-{ }
 #endif
 
-static int class_uevent(struct kset *kset, struct kobject *kobj,
-                       struct kobj_uevent_env *env)
-{
-       struct class_device *class_dev = to_class_dev(kobj);
-       struct device *dev = class_dev->dev;
-       int retval = 0;
-
-       pr_debug("%s - name = %s\n", __func__, class_dev->class_id);
-
-       if (MAJOR(class_dev->devt)) {
-               add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
-
-               add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
-       }
-
-       if (dev) {
-               const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
-               if (path) {
-                       add_uevent_var(env, "PHYSDEVPATH=%s", path);
-                       kfree(path);
-               }
-
-               if (dev->bus)
-                       add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
-
-               if (dev->driver)
-                       add_uevent_var(env, "PHYSDEVDRIVER=%s",
-                                      dev->driver->name);
-       }
-
-       if (class_dev->uevent) {
-               /* have the class device specific function add its stuff */
-               retval = class_dev->uevent(class_dev, env);
-               if (retval)
-                       pr_debug("class_dev->uevent() returned %d\n", retval);
-       } else if (class_dev->class->uevent) {
-               /* have the class specific function add its stuff */
-               retval = class_dev->class->uevent(class_dev, env);
-               if (retval)
-                       pr_debug("class->uevent() returned %d\n", retval);
-       }
-
-       return retval;
-}
-
-static struct kset_uevent_ops class_uevent_ops = {
-       .filter =       class_uevent_filter,
-       .name =         class_uevent_name,
-       .uevent =       class_uevent,
-};
-
-/*
- * DO NOT copy how this is created, kset_create_and_add() should be
- * called, but this is a hold-over from the old-way and will be deleted
- * entirely soon.
- */
-static struct kset class_obj_subsys = {
-       .uevent_ops = &class_uevent_ops,
-};
-
-static int class_device_add_attrs(struct class_device *cd)
-{
-       int i;
-       int error = 0;
-       struct class *cls = cd->class;
-
-       if (cls->class_dev_attrs) {
-               for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
-                       error = class_device_create_file(cd,
-                                               &cls->class_dev_attrs[i]);
-                       if (error)
-                               goto err;
-               }
-       }
-done:
-       return error;
-err:
-       while (--i >= 0)
-               class_device_remove_file(cd, &cls->class_dev_attrs[i]);
-       goto done;
-}
-
-static void class_device_remove_attrs(struct class_device *cd)
-{
-       int i;
-       struct class *cls = cd->class;
-
-       if (cls->class_dev_attrs) {
-               for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
-                       class_device_remove_file(cd, &cls->class_dev_attrs[i]);
-       }
-}
-
-static int class_device_add_groups(struct class_device *cd)
-{
-       int i;
-       int error = 0;
-
-       if (cd->groups) {
-               for (i = 0; cd->groups[i]; i++) {
-                       error = sysfs_create_group(&cd->kobj, cd->groups[i]);
-                       if (error) {
-                               while (--i >= 0)
-                                       sysfs_remove_group(&cd->kobj,
-                                                          cd->groups[i]);
-                               goto out;
-                       }
-               }
-       }
-out:
-       return error;
-}
-
-static void class_device_remove_groups(struct class_device *cd)
-{
-       int i;
-       if (cd->groups)
-               for (i = 0; cd->groups[i]; i++)
-                       sysfs_remove_group(&cd->kobj, cd->groups[i]);
-}
-
-static ssize_t show_dev(struct class_device *class_dev, char *buf)
-{
-       return print_dev_t(buf, class_dev->devt);
-}
-
-static struct class_device_attribute class_devt_attr =
-       __ATTR(dev, S_IRUGO, show_dev, NULL);
-
-static ssize_t store_uevent(struct class_device *class_dev,
-                           const char *buf, size_t count)
-{
-       kobject_uevent(&class_dev->kobj, KOBJ_ADD);
-       return count;
-}
-
-static struct class_device_attribute class_uevent_attr =
-       __ATTR(uevent, S_IWUSR, NULL, store_uevent);
-
-void class_device_initialize(struct class_device *class_dev)
-{
-       class_dev->kobj.kset = &class_obj_subsys;
-       kobject_init(&class_dev->kobj, &class_device_ktype);
-       INIT_LIST_HEAD(&class_dev->node);
-}
-
-int class_device_add(struct class_device *class_dev)
-{
-       struct class *parent_class = NULL;
-       struct class_device *parent_class_dev = NULL;
-       struct class_interface *class_intf;
-       int error = -EINVAL;
-
-       class_dev = class_device_get(class_dev);
-       if (!class_dev)
-               return -EINVAL;
-
-       if (!strlen(class_dev->class_id))
-               goto out1;
-
-       parent_class = class_get(class_dev->class);
-       if (!parent_class)
-               goto out1;
-
-       parent_class_dev = class_device_get(class_dev->parent);
-
-       pr_debug("CLASS: registering class device: ID = '%s'\n",
-                class_dev->class_id);
-
-       /* first, register with generic layer. */
-       if (parent_class_dev)
-               class_dev->kobj.parent = &parent_class_dev->kobj;
-       else
-               class_dev->kobj.parent = &parent_class->subsys.kobj;
-
-       error = kobject_add(&class_dev->kobj, class_dev->kobj.parent,
-                           "%s", class_dev->class_id);
-       if (error)
-               goto out2;
-
-       /* add the needed attributes to this device */
-       error = sysfs_create_link(&class_dev->kobj,
-                                 &parent_class->subsys.kobj, "subsystem");
-       if (error)
-               goto out3;
-
-       error = class_device_create_file(class_dev, &class_uevent_attr);
-       if (error)
-               goto out3;
-
-       if (MAJOR(class_dev->devt)) {
-               error = class_device_create_file(class_dev, &class_devt_attr);
-               if (error)
-                       goto out4;
-       }
-
-       error = class_device_add_attrs(class_dev);
-       if (error)
-               goto out5;
-
-       if (class_dev->dev) {
-               error = sysfs_create_link(&class_dev->kobj,
-                                         &class_dev->dev->kobj, "device");
-               if (error)
-                       goto out6;
-       }
-
-       error = class_device_add_groups(class_dev);
-       if (error)
-               goto out7;
-
-       error = make_deprecated_class_device_links(class_dev);
-       if (error)
-               goto out8;
-
-       kobject_uevent(&class_dev->kobj, KOBJ_ADD);
-
-       /* notify any interfaces this device is now here */
-       down(&parent_class->sem);
-       list_add_tail(&class_dev->node, &parent_class->children);
-       list_for_each_entry(class_intf, &parent_class->interfaces, node) {
-               if (class_intf->add)
-                       class_intf->add(class_dev, class_intf);
-       }
-       up(&parent_class->sem);
-
-       goto out1;
-
- out8:
-       class_device_remove_groups(class_dev);
- out7:
-       if (class_dev->dev)
-               sysfs_remove_link(&class_dev->kobj, "device");
- out6:
-       class_device_remove_attrs(class_dev);
- out5:
-       if (MAJOR(class_dev->devt))
-               class_device_remove_file(class_dev, &class_devt_attr);
- out4:
-       class_device_remove_file(class_dev, &class_uevent_attr);
- out3:
-       kobject_del(&class_dev->kobj);
- out2:
-       if (parent_class_dev)
-               class_device_put(parent_class_dev);
-       class_put(parent_class);
- out1:
-       class_device_put(class_dev);
-       return error;
-}
-
-int class_device_register(struct class_device *class_dev)
-{
-       class_device_initialize(class_dev);
-       return class_device_add(class_dev);
-}
-
-/**
- * class_device_create - creates a class device and registers it with sysfs
- * @cls: pointer to the struct class that this device should be registered to.
- * @parent: pointer to the parent struct class_device of this new device, if
- * any.
- * @devt: the dev_t for the char device to be added.
- * @device: a pointer to a struct device that is assiociated with this class
- * device.
- * @fmt: string for the class device's name
- *
- * This function can be used by char device classes.  A struct
- * class_device will be created in sysfs, registered to the specified
- * class.
- * A "dev" file will be created, showing the dev_t for the device, if
- * the dev_t is not 0,0.
- * If a pointer to a parent struct class_device is passed in, the newly
- * created struct class_device will be a child of that device in sysfs.
- * The pointer to the struct class_device will be returned from the
- * call.  Any further sysfs files that might be required can be created
- * using this pointer.
- *
- * Note: the struct class passed to this function must have previously
- * been created with a call to class_create().
- */
-struct class_device *class_device_create(struct class *cls,
-                                        struct class_device *parent,
-                                        dev_t devt,
-                                        struct device *device,
-                                        const char *fmt, ...)
-{
-       va_list args;
-       struct class_device *class_dev = NULL;
-       int retval = -ENODEV;
-
-       if (cls == NULL || IS_ERR(cls))
-               goto error;
-
-       class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
-       if (!class_dev) {
-               retval = -ENOMEM;
-               goto error;
-       }
-
-       class_dev->devt = devt;
-       class_dev->dev = device;
-       class_dev->class = cls;
-       class_dev->parent = parent;
-       class_dev->release = class_device_create_release;
-       class_dev->uevent = class_device_create_uevent;
-
-       va_start(args, fmt);
-       vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
-       va_end(args);
-       retval = class_device_register(class_dev);
-       if (retval)
-               goto error;
-
-       return class_dev;
-
-error:
-       kfree(class_dev);
-       return ERR_PTR(retval);
-}
-
-void class_device_del(struct class_device *class_dev)
-{
-       struct class *parent_class = class_dev->class;
-       struct class_device *parent_device = class_dev->parent;
-       struct class_interface *class_intf;
-
-       if (parent_class) {
-               down(&parent_class->sem);
-               list_del_init(&class_dev->node);
-               list_for_each_entry(class_intf, &parent_class->interfaces, node)
-                       if (class_intf->remove)
-                               class_intf->remove(class_dev, class_intf);
-               up(&parent_class->sem);
-       }
-
-       if (class_dev->dev) {
-               remove_deprecated_class_device_links(class_dev);
-               sysfs_remove_link(&class_dev->kobj, "device");
-       }
-       sysfs_remove_link(&class_dev->kobj, "subsystem");
-       class_device_remove_file(class_dev, &class_uevent_attr);
-       if (MAJOR(class_dev->devt))
-               class_device_remove_file(class_dev, &class_devt_attr);
-       class_device_remove_attrs(class_dev);
-       class_device_remove_groups(class_dev);
-
-       kobject_uevent(&class_dev->kobj, KOBJ_REMOVE);
-       kobject_del(&class_dev->kobj);
-
-       class_device_put(parent_device);
-       class_put(parent_class);
-}
-
-void class_device_unregister(struct class_device *class_dev)
-{
-       pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
-                class_dev->class_id);
-       class_device_del(class_dev);
-       class_device_put(class_dev);
-}
-
-/**
- * class_device_destroy - removes a class device that was created with class_device_create()
- * @cls: the pointer to the struct class that this device was registered * with.
- * @devt: the dev_t of the device that was previously registered.
- *
- * This call unregisters and cleans up a class device that was created with a
- * call to class_device_create()
- */
-void class_device_destroy(struct class *cls, dev_t devt)
-{
-       struct class_device *class_dev = NULL;
-       struct class_device *class_dev_tmp;
-
-       down(&cls->sem);
-       list_for_each_entry(class_dev_tmp, &cls->children, node) {
-               if (class_dev_tmp->devt == devt) {
-                       class_dev = class_dev_tmp;
-                       break;
-               }
-       }
-       up(&cls->sem);
-
-       if (class_dev)
-               class_device_unregister(class_dev);
-}
-
-struct class_device *class_device_get(struct class_device *class_dev)
-{
-       if (class_dev)
-               return to_class_dev(kobject_get(&class_dev->kobj));
-       return NULL;
-}
-
-void class_device_put(struct class_device *class_dev)
-{
-       if (class_dev)
-               kobject_put(&class_dev->kobj);
-}
-
 /**
  * class_for_each_device - device iterator
  * @class: the class we're iterating
@@ -897,56 +338,9 @@ struct device *class_find_device(struct class *class, void *data,
 }
 EXPORT_SYMBOL_GPL(class_find_device);
 
-/**
- * class_find_child - device iterator for locating a particular class_device
- * @class: the class we're iterating
- * @data: data for the match function
- * @match: function to check class_device
- *
- * This function returns a reference to a class_device that is 'found' for
- * later use, as determined by the @match callback.
- *
- * The callback should return 0 if the class_device doesn't match and non-zero
- * if it does.  If the callback returns non-zero, this function will
- * return to the caller and not iterate over any more class_devices.
- *
- * Note, you will need to drop the reference with class_device_put() after use.
- *
- * We hold class->sem in this function, so it can not be
- * re-acquired in @match, otherwise it will self-deadlocking. For
- * example, calls to add or remove class members would be verboten.
- */
-struct class_device *class_find_child(struct class *class, void *data,
-                                  int (*match)(struct class_device *, void *))
-{
-       struct class_device *dev;
-       int found = 0;
-
-       if (!class)
-               return NULL;
-
-       down(&class->sem);
-       list_for_each_entry(dev, &class->children, node) {
-               dev = class_device_get(dev);
-               if (dev) {
-                       if (match(dev, data)) {
-                               found = 1;
-                               break;
-                       } else
-                               class_device_put(dev);
-               } else
-                       break;
-       }
-       up(&class->sem);
-
-       return found ? dev : NULL;
-}
-EXPORT_SYMBOL_GPL(class_find_child);
-
 int class_interface_register(struct class_interface *class_intf)
 {
        struct class *parent;
-       struct class_device *class_dev;
        struct device *dev;
 
        if (!class_intf || !class_intf->class)
@@ -958,10 +352,6 @@ int class_interface_register(struct class_interface *class_intf)
 
        down(&parent->sem);
        list_add_tail(&class_intf->node, &parent->interfaces);
-       if (class_intf->add) {
-               list_for_each_entry(class_dev, &parent->children, node)
-                       class_intf->add(class_dev, class_intf);
-       }
        if (class_intf->add_dev) {
                list_for_each_entry(dev, &parent->devices, node)
                        class_intf->add_dev(dev, class_intf);
@@ -974,7 +364,6 @@ int class_interface_register(struct class_interface *class_intf)
 void class_interface_unregister(struct class_interface *class_intf)
 {
        struct class *parent = class_intf->class;
-       struct class_device *class_dev;
        struct device *dev;
 
        if (!parent)
@@ -982,10 +371,6 @@ void class_interface_unregister(struct class_interface *class_intf)
 
        down(&parent->sem);
        list_del_init(&class_intf->node);
-       if (class_intf->remove) {
-               list_for_each_entry(class_dev, &parent->children, node)
-                       class_intf->remove(class_dev, class_intf);
-       }
        if (class_intf->remove_dev) {
                list_for_each_entry(dev, &parent->devices, node)
                        class_intf->remove_dev(dev, class_intf);
@@ -1000,13 +385,6 @@ int __init classes_init(void)
        class_kset = kset_create_and_add("class", NULL, NULL);
        if (!class_kset)
                return -ENOMEM;
-
-       /* ick, this is ugly, the things we go through to keep from showing up
-        * in sysfs... */
-       kset_init(&class_obj_subsys);
-       kobject_set_name(&class_obj_subsys.kobj, "class_obj");
-       if (!class_obj_subsys.kobj.parent)
-               class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
        return 0;
 }
 
@@ -1017,19 +395,5 @@ EXPORT_SYMBOL_GPL(class_unregister);
 EXPORT_SYMBOL_GPL(class_create);
 EXPORT_SYMBOL_GPL(class_destroy);
 
-EXPORT_SYMBOL_GPL(class_device_register);
-EXPORT_SYMBOL_GPL(class_device_unregister);
-EXPORT_SYMBOL_GPL(class_device_initialize);
-EXPORT_SYMBOL_GPL(class_device_add);
-EXPORT_SYMBOL_GPL(class_device_del);
-EXPORT_SYMBOL_GPL(class_device_get);
-EXPORT_SYMBOL_GPL(class_device_put);
-EXPORT_SYMBOL_GPL(class_device_create);
-EXPORT_SYMBOL_GPL(class_device_destroy);
-EXPORT_SYMBOL_GPL(class_device_create_file);
-EXPORT_SYMBOL_GPL(class_device_remove_file);
-EXPORT_SYMBOL_GPL(class_device_create_bin_file);
-EXPORT_SYMBOL_GPL(class_device_remove_bin_file);
-
 EXPORT_SYMBOL_GPL(class_interface_register);
 EXPORT_SYMBOL_GPL(class_interface_unregister);
index 6fe417429977058b40f9ac2caee0b5b933078070..e38dfed41d80b8e6dff45379ee1fdfb8e8d3c750 100644 (file)
@@ -18,7 +18,7 @@ struct sysdev_class cpu_sysdev_class = {
 };
 EXPORT_SYMBOL(cpu_sysdev_class);
 
-static struct sys_device *cpu_sys_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct sys_device *, cpu_sys_devices);
 
 #ifdef CONFIG_HOTPLUG_CPU
 static ssize_t show_online(struct sys_device *dev, char *buf)
@@ -68,7 +68,7 @@ void unregister_cpu(struct cpu *cpu)
        sysdev_remove_file(&cpu->sysdev, &attr_online);
 
        sysdev_unregister(&cpu->sysdev);
-       cpu_sys_devices[logical_cpu] = NULL;
+       per_cpu(cpu_sys_devices, logical_cpu) = NULL;
        return;
 }
 #else /* ... !CONFIG_HOTPLUG_CPU */
@@ -167,7 +167,7 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
        if (!error && cpu->hotpluggable)
                register_cpu_control(cpu);
        if (!error)
-               cpu_sys_devices[num] = &cpu->sysdev;
+               per_cpu(cpu_sys_devices, num) = &cpu->sysdev;
        if (!error)
                register_cpu_under_node(num, cpu_to_node(num));
 
@@ -180,8 +180,8 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
 
 struct sys_device *get_cpu_sysdev(unsigned cpu)
 {
-       if (cpu < NR_CPUS)
-               return cpu_sys_devices[cpu];
+       if (cpu < nr_cpu_ids && cpu_possible(cpu))
+               return per_cpu(cpu_sys_devices, cpu);
        else
                return NULL;
 }
index 9a6537f14401df5aae7a81842c7bd7a145c2f849..2ef5acf4368b9e8deef4440d865a87cef8d0b0a6 100644 (file)
@@ -217,12 +217,22 @@ static void driver_remove_groups(struct device_driver *drv,
 int driver_register(struct device_driver *drv)
 {
        int ret;
+       struct device_driver *other;
 
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown))
                printk(KERN_WARNING "Driver '%s' needs updating - please use "
                        "bus_type methods\n", drv->name);
+
+       other = driver_find(drv->name, drv->bus);
+       if (other) {
+               put_driver(other);
+               printk(KERN_ERR "Error: Driver '%s' is already registered, "
+                       "aborting...\n", drv->name);
+               return -EEXIST;
+       }
+
        ret = bus_add_driver(drv);
        if (ret)
                return ret;
index e539be5750dc694703af89853fee7a41ffed5bac..e336b05fe4a7f5d763dd0db8c61dc740b93635a9 100644 (file)
@@ -428,13 +428,9 @@ static void __devinit cciss_procinit(int i)
                proc_cciss = proc_mkdir("driver/cciss", NULL);
        if (!proc_cciss)
                return;
-       pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
+       pde = proc_create_data(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
                                        S_IROTH, proc_cciss,
-                                       &cciss_proc_fops);
-       if (!pde)
-               return;
-
-       pde->data = hba[i];
+                                       &cciss_proc_fops, hba[i]);
 }
 #endif                         /* CONFIG_PROC_FS */
 
index e322cce8c12d7870d45b2b202c8ff60e9e924c9f..3a281ef11ffa9a96543358dc91c817805eedc981 100644 (file)
@@ -205,6 +205,7 @@ struct ub_scsi_cmd {
        unsigned char key, asc, ascq;   /* May be valid if error==-EIO */
 
        int stat_count;                 /* Retries getting status. */
+       unsigned int timeo;             /* jiffies until rq->timeout changes */
 
        unsigned int len;               /* Requested length */
        unsigned int current_sg;
@@ -318,6 +319,7 @@ struct ub_dev {
        int openc;                      /* protected by ub_lock! */
                                        /* kref is too implicit for our taste */
        int reset;                      /* Reset is running */
+       int bad_resid;
        unsigned int tagcnt;
        char name[12];
        struct usb_device *dev;
@@ -764,6 +766,12 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
        cmd->cdb_len = rq->cmd_len;
 
        cmd->len = rq->data_len;
+
+       /*
+        * To reapply this to every URB is not as incorrect as it looks.
+        * In return, we avoid any complicated tracking calculations.
+        */
+       cmd->timeo = rq->timeout;
 }
 
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
@@ -785,10 +793,6 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        scsi_status = 0;
                } else {
                        if (cmd->act_len != cmd->len) {
-                               if ((cmd->key == MEDIUM_ERROR ||
-                                    cmd->key == UNIT_ATTENTION) &&
-                                   ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
-                                       return;
                                scsi_status = SAM_STAT_CHECK_CONDITION;
                        } else {
                                scsi_status = 0;
@@ -804,7 +808,10 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        else
                                scsi_status = DID_ERROR << 16;
                } else {
-                       if (cmd->error == -EIO) {
+                       if (cmd->error == -EIO &&
+                           (cmd->key == 0 ||
+                            cmd->key == MEDIUM_ERROR ||
+                            cmd->key == UNIT_ATTENTION)) {
                                if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
                                        return;
                        }
@@ -1259,14 +1266,19 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                        return;
                }
 
-               len = le32_to_cpu(bcs->Residue);
-               if (len != cmd->len - cmd->act_len) {
-                       /*
-                        * It is all right to transfer less, the caller has
-                        * to check. But it's not all right if the device
-                        * counts disagree with our counts.
-                        */
-                       goto Bad_End;
+               if (!sc->bad_resid) {
+                       len = le32_to_cpu(bcs->Residue);
+                       if (len != cmd->len - cmd->act_len) {
+                               /*
+                                * Only start ignoring if this cmd ended well.
+                                */
+                               if (cmd->len == cmd->act_len) {
+                                       printk(KERN_NOTICE "%s: "
+                                           "bad residual %d of %d, ignoring\n",
+                                           sc->name, len, cmd->len);
+                                       sc->bad_resid = 1;
+                               }
+                       }
                }
 
                switch (bcs->Status) {
@@ -1297,8 +1309,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                ub_state_done(sc, cmd, -EIO);
 
        } else {
-               printk(KERN_WARNING "%s: "
-                   "wrong command state %d\n",
+               printk(KERN_WARNING "%s: wrong command state %d\n",
                    sc->name, cmd->state);
                ub_state_done(sc, cmd, -EINVAL);
                return;
@@ -1336,7 +1347,10 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                return;
        }
 
-       sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+       if (cmd->timeo)
+               sc->work_timer.expires = jiffies + cmd->timeo;
+       else
+               sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
        add_timer(&sc->work_timer);
 
        cmd->state = UB_CMDST_DATA;
@@ -1376,7 +1390,10 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
                return -1;
        }
 
-       sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
+       if (cmd->timeo)
+               sc->work_timer.expires = jiffies + cmd->timeo;
+       else
+               sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
        add_timer(&sc->work_timer);
        return 0;
 }
@@ -1515,8 +1532,7 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
                return;
        }
        if (cmd->state != UB_CMDST_SENSE) {
-               printk(KERN_WARNING "%s: "
-                   "sense done with bad cmd state %d\n",
+               printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
                    sc->name, cmd->state);
                return;
        }
@@ -1720,7 +1736,7 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp,
 }
 
 /*
- * This is called once a new disk was seen by the block layer or by ub_probe().
+ * This is called by check_disk_change if we reported a media change.
  * The main onjective here is to discover the features of the media such as
  * the capacity, read-only status, etc. USB storage generally does not
  * need to be spun up, but if we needed it, this would be the place.
@@ -2136,8 +2152,7 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
        }
 
        if (ep_in == NULL || ep_out == NULL) {
-               printk(KERN_NOTICE "%s: failed endpoint check\n",
-                   sc->name);
+               printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
                return -ENODEV;
        }
 
@@ -2354,7 +2369,7 @@ static void ub_disconnect(struct usb_interface *intf)
        spin_unlock_irqrestore(&ub_lock, flags);
 
        /*
-        * Fence stall clearnings, operations triggered by unlinkings and so on.
+        * Fence stall clearings, operations triggered by unlinkings and so on.
         * We do not attempt to unlink any URBs, because we do not trust the
         * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
         */
@@ -2417,7 +2432,7 @@ static void ub_disconnect(struct usb_interface *intf)
        spin_unlock_irqrestore(sc->lock, flags);
 
        /*
-        * There is virtually no chance that other CPU runs times so long
+        * There is virtually no chance that other CPU runs a timeout so long
         * after ub_urb_complete should have called del_timer, but only if HCD
         * didn't forget to deliver a callback on unlink.
         */
index 0cfbe8c594a55c208a7727cc20a86db0e33ba704..84e064ffee5229e73d2f9f45af19a3ec581f5315 100644 (file)
@@ -35,7 +35,7 @@ struct virtblk_req
        struct list_head list;
        struct request *req;
        struct virtio_blk_outhdr out_hdr;
-       struct virtio_blk_inhdr in_hdr;
+       u8 status;
 };
 
 static void blk_done(struct virtqueue *vq)
@@ -48,7 +48,7 @@ static void blk_done(struct virtqueue *vq)
        spin_lock_irqsave(&vblk->lock, flags);
        while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
                int uptodate;
-               switch (vbr->in_hdr.status) {
+               switch (vbr->status) {
                case VIRTIO_BLK_S_OK:
                        uptodate = 1;
                        break;
@@ -101,7 +101,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
        sg_init_table(vblk->sg, VIRTIO_MAX_SG);
        sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
        num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
-       sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr));
+       sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
 
        if (rq_data_dir(vbr->req) == WRITE) {
                vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
@@ -157,10 +157,25 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp,
 /* We provide getgeo only to please some old bootloader/partitioning tools */
 static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 {
-       /* some standard values, similar to sd */
-       geo->heads = 1 << 6;
-       geo->sectors = 1 << 5;
-       geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+       struct virtio_blk *vblk = bd->bd_disk->private_data;
+       struct virtio_blk_geometry vgeo;
+       int err;
+
+       /* see if the host passed in geometry config */
+       err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
+                               offsetof(struct virtio_blk_config, geometry),
+                               &vgeo);
+
+       if (!err) {
+               geo->heads = vgeo.heads;
+               geo->sectors = vgeo.sectors;
+               geo->cylinders = vgeo.cylinders;
+       } else {
+               /* some standard values, similar to sd */
+               geo->heads = 1 << 6;
+               geo->sectors = 1 << 5;
+               geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+       }
        return 0;
 }
 
@@ -242,12 +257,12 @@ static int virtblk_probe(struct virtio_device *vdev)
        index++;
 
        /* If barriers are supported, tell block layer that queue is ordered */
-       if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
+       if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
                blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
 
        /* Host must always specify the capacity. */
-       __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
-                           &cap);
+       vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
+                         &cap, sizeof(cap));
 
        /* If capacity is too big, truncate with warning. */
        if ((sector_t)cap != cap) {
@@ -289,7 +304,6 @@ out:
 static void virtblk_remove(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk = vdev->priv;
-       int major = vblk->disk->major;
 
        /* Nothing should be pending. */
        BUG_ON(!list_empty(&vblk->reqs));
@@ -299,7 +313,6 @@ static void virtblk_remove(struct virtio_device *vdev)
 
        blk_cleanup_queue(vblk->disk->queue);
        put_disk(vblk->disk);
-       unregister_blkdev(major, "virtblk");
        mempool_destroy(vblk->pool);
        vdev->config->del_vq(vblk->vq);
        kfree(vblk);
@@ -310,7 +323,14 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
+static unsigned int features[] = {
+       VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
+       VIRTIO_BLK_F_GEOMETRY,
+};
+
 static struct virtio_driver virtio_blk = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
index f49037b744f99ef52455bfad7588f5d1610b7c35..b60d425ce8d1502fcadcfba5350770525d9be2dd 100644 (file)
@@ -77,6 +77,10 @@ static int power_status;
 module_param(power_status, bool, 0600);
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
+static int fan_mult = I8K_FAN_MULT;
+module_param(fan_mult, int, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
+
 static int i8k_open_fs(struct inode *inode, struct file *file);
 static int i8k_ioctl(struct inode *, struct file *, unsigned int,
                     unsigned long);
@@ -239,7 +243,7 @@ static int i8k_get_fan_speed(int fan)
        struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
 
        regs.ebx = fan & 0xff;
-       return i8k_smm(&regs) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
+       return i8k_smm(&regs) ? : (regs.eax & 0xffff) * fan_mult;
 }
 
 /*
index d83db5d880e068ac4296c2b07767d849067a1037..192961fd71739d22ad4ff9a65df5a101bc460fbd 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/miscdevice.h>
 #include <linux/posix-timers.h>
 #include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/math64.h>
 
 #include <asm/uaccess.h>
 #include <asm/sn/addrs.h>
@@ -472,8 +474,8 @@ static int sgi_clock_get(clockid_t clockid, struct timespec *tp)
 
        nsec = rtc_time() * sgi_clock_period
                        + sgi_clock_offset.tv_nsec;
-       tp->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tp->tv_nsec)
-                       + sgi_clock_offset.tv_sec;
+       *tp = ns_to_timespec(nsec);
+       tp->tv_sec += sgi_clock_offset.tv_sec;
        return 0;
 };
 
@@ -481,11 +483,11 @@ static int sgi_clock_set(clockid_t clockid, struct timespec *tp)
 {
 
        u64 nsec;
-       u64 rem;
+       u32 rem;
 
        nsec = rtc_time() * sgi_clock_period;
 
-       sgi_clock_offset.tv_sec = tp->tv_sec - div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+       sgi_clock_offset.tv_sec = tp->tv_sec - div_u64_rem(nsec, NSEC_PER_SEC, &rem);
 
        if (rem <= tp->tv_nsec)
                sgi_clock_offset.tv_nsec = tp->tv_sec - rem;
@@ -644,9 +646,6 @@ static int sgi_timer_del(struct k_itimer *timr)
        return 0;
 }
 
-#define timespec_to_ns(x) ((x).tv_nsec + (x).tv_sec * NSEC_PER_SEC)
-#define ns_to_timespec(ts, nsec) (ts).tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &(ts).tv_nsec)
-
 /* Assumption: it_lock is already held with irq's disabled */
 static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
 {
@@ -659,9 +658,8 @@ static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
                return;
        }
 
-       ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period);
-       ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period);
-       return;
+       cur_setting->it_interval = ns_to_timespec(timr->it.mmtimer.incr * sgi_clock_period);
+       cur_setting->it_value = ns_to_timespec((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period);
 }
 
 
@@ -679,8 +677,8 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
                sgi_timer_get(timr, old_setting);
 
        sgi_timer_del(timr);
-       when = timespec_to_ns(new_setting->it_value);
-       period = timespec_to_ns(new_setting->it_interval);
+       when = timespec_to_ns(&new_setting->it_value);
+       period = timespec_to_ns(&new_setting->it_interval);
 
        if (when == 0)
                /* Clear timer */
@@ -695,7 +693,7 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
                unsigned long now;
 
                getnstimeofday(&n);
-               now = timespec_to_ns(n);
+               now = timespec_to_ns(&n);
                if (when > now)
                        when -= now;
                else
index 513b7c2f3e264fc2dd809c7865ebd4b0dd66ee53..ac5080df2565aef4cd85e96a112d3cd3ffa7820f 100644 (file)
@@ -2028,13 +2028,13 @@ static void mgsl_change_params(struct mgsl_struct *info)
  */
 static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
-       int ret;
+       int ret = 0;
 
-       if ( debug_level >= DEBUG_LEVEL_INFO ) {
-               printk( "%s(%d):mgsl_put_char(%d) on %s\n",
-                       __FILE__,__LINE__,ch,info->device_name);
+       if (debug_level >= DEBUG_LEVEL_INFO) {
+               printk(KERN_DEBUG "%s(%d):mgsl_put_char(%d) on %s\n",
+                       __FILE__, __LINE__, ch, info->device_name);
        }               
        
        if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char"))
@@ -2043,9 +2043,9 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
        if (!tty || !info->xmit_buf)
                return 0;
 
-       spin_lock_irqsave(&info->irq_spinlock,flags);
+       spin_lock_irqsave(&info->irq_spinlock, flags);
        
-       if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) {
+       if ((info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active) {
                if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) {
                        info->xmit_buf[info->xmit_head++] = ch;
                        info->xmit_head &= SERIAL_XMIT_SIZE-1;
@@ -2053,7 +2053,7 @@ static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
                        ret = 1;
                }
        }
-       spin_unlock_irqrestore(&info->irq_spinlock,flags);
+       spin_unlock_irqrestore(&info->irq_spinlock, flags);
        return ret;
        
 }      /* end of mgsl_put_char() */
index 64f1ceed0b2cbb3d4f72b8faad3a8459821f3ad0..663cd15d7c78fa5a0cbd548179f61b352ba53e38 100644 (file)
@@ -426,7 +426,7 @@ static int tosh_probe(void)
        int i,major,minor,day,year,month,flag;
        unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 };
        SMMRegisters regs;
-       void __iomem *bios = ioremap(0xf0000, 0x10000);
+       void __iomem *bios = ioremap_cache(0xf0000, 0x10000);
 
        if (!bios)
                return -ENOMEM;
index 6342b0534f4d3cda24aaac72cd5cb25deeb3021d..3582f43345a8c1d40397d2284dd2bc11d77a9fd4 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/audit.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/tty.h>
 
 struct tty_audit_buf {
index 1d298c2cf9301c0a1ac2026577463e6a3a6b1813..49c1a2267a55c7490c504ba7486b276575851ae8 100644 (file)
@@ -78,6 +78,7 @@
 #include <linux/tty_flip.h>
 #include <linux/devpts_fs.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/console.h>
 #include <linux/timer.h>
 #include <linux/ctype.h>
index 2a999373863eb206927d23e4a8f775cf3c92c053..b2458bb8e9cade2fd79fea620b60eb9edd0aa7e0 100644 (file)
@@ -784,7 +784,7 @@ static void sbp2_release_target(struct kref *kref)
                kfree(lu);
        }
        scsi_remove_host(shost);
-       fw_notify("released %s\n", tgt->bus_id);
+       fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no);
 
        fw_unit_put(tgt->unit);
        scsi_host_put(shost);
@@ -1487,7 +1487,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
        if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0)
                goto out;
 
-       memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+       memcpy(orb->request.command_block, cmd->cmnd, cmd->cmd_len);
 
        orb->base.callback = complete_command_orb;
        orb->base.request_bus =
index 5a99e81d27843c8ce9e376684196b5daa253f90a..93f916720b139e40b20591839126609db0e778a0 100644 (file)
@@ -30,6 +30,8 @@ static const struct i2c_device_id pca953x_id[] = {
        { "pca9537", 4, },
        { "pca9538", 8, },
        { "pca9539", 16, },
+       { "pca9555", 16, },
+       { "pca9557", 8, },
        /* REVISIT several pca955x parts should work here too */
        { }
 };
@@ -193,7 +195,7 @@ static int __devinit pca953x_probe(struct i2c_client *client,
 {
        struct pca953x_platform_data *pdata;
        struct pca953x_chip *chip;
-       int ret, i;
+       int ret;
 
        pdata = client->dev.platform_data;
        if (pdata == NULL)
index 9587869bdba0eb5bf58314b56c76d98f91b28507..c1009d6f97965b160d26ac4723235d97280a427c 100644 (file)
@@ -422,18 +422,14 @@ static ssize_t show_volt(struct device *dev, struct device_attribute *devattr,
  * number in the range -128 to 127, or as an unsigned number that must
  * be offset by 64.
  */
-static int decode_temp(struct adt7473_data *data, u8 raw)
+static int decode_temp(u8 twos_complement, u8 raw)
 {
-       if (data->temp_twos_complement)
-               return (s8)raw;
-       return raw - 64;
+       return twos_complement ? (s8)raw : raw - 64;
 }
 
-static u8 encode_temp(struct adt7473_data *data, int cooked)
+static u8 encode_temp(u8 twos_complement, int cooked)
 {
-       if (data->temp_twos_complement)
-               return (cooked & 0xFF);
-       return cooked + 64;
+       return twos_complement ? cooked & 0xFF : cooked + 64;
 }
 
 static ssize_t show_temp_min(struct device *dev,
@@ -442,8 +438,9 @@ static ssize_t show_temp_min(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct adt7473_data *data = adt7473_update_device(dev);
-       return sprintf(buf, "%d\n",
-                      1000 * decode_temp(data, data->temp_min[attr->index]));
+       return sprintf(buf, "%d\n", 1000 * decode_temp(
+                                               data->temp_twos_complement,
+                                               data->temp_min[attr->index]));
 }
 
 static ssize_t set_temp_min(struct device *dev,
@@ -455,7 +452,7 @@ static ssize_t set_temp_min(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
        int temp = simple_strtol(buf, NULL, 10) / 1000;
-       temp = encode_temp(data, temp);
+       temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
        data->temp_min[attr->index] = temp;
@@ -472,8 +469,9 @@ static ssize_t show_temp_max(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct adt7473_data *data = adt7473_update_device(dev);
-       return sprintf(buf, "%d\n",
-                      1000 * decode_temp(data, data->temp_max[attr->index]));
+       return sprintf(buf, "%d\n", 1000 * decode_temp(
+                                               data->temp_twos_complement,
+                                               data->temp_max[attr->index]));
 }
 
 static ssize_t set_temp_max(struct device *dev,
@@ -485,7 +483,7 @@ static ssize_t set_temp_max(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
        int temp = simple_strtol(buf, NULL, 10) / 1000;
-       temp = encode_temp(data, temp);
+       temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
        data->temp_max[attr->index] = temp;
@@ -501,8 +499,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct adt7473_data *data = adt7473_update_device(dev);
-       return sprintf(buf, "%d\n",
-                      1000 * decode_temp(data, data->temp[attr->index]));
+       return sprintf(buf, "%d\n", 1000 * decode_temp(
+                                               data->temp_twos_complement,
+                                               data->temp[attr->index]));
 }
 
 static ssize_t show_fan_min(struct device *dev,
@@ -671,8 +670,9 @@ static ssize_t show_temp_tmax(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct adt7473_data *data = adt7473_update_device(dev);
-       return sprintf(buf, "%d\n",
-                      1000 * decode_temp(data, data->temp_tmax[attr->index]));
+       return sprintf(buf, "%d\n", 1000 * decode_temp(
+                                               data->temp_twos_complement,
+                                               data->temp_tmax[attr->index]));
 }
 
 static ssize_t set_temp_tmax(struct device *dev,
@@ -684,7 +684,7 @@ static ssize_t set_temp_tmax(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
        int temp = simple_strtol(buf, NULL, 10) / 1000;
-       temp = encode_temp(data, temp);
+       temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
        data->temp_tmax[attr->index] = temp;
@@ -701,8 +701,9 @@ static ssize_t show_temp_tmin(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct adt7473_data *data = adt7473_update_device(dev);
-       return sprintf(buf, "%d\n",
-                      1000 * decode_temp(data, data->temp_tmin[attr->index]));
+       return sprintf(buf, "%d\n", 1000 * decode_temp(
+                                               data->temp_twos_complement,
+                                               data->temp_tmin[attr->index]));
 }
 
 static ssize_t set_temp_tmin(struct device *dev,
@@ -714,7 +715,7 @@ static ssize_t set_temp_tmin(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7473_data *data = i2c_get_clientdata(client);
        int temp = simple_strtol(buf, NULL, 10) / 1000;
-       temp = encode_temp(data, temp);
+       temp = encode_temp(data->temp_twos_complement, temp);
 
        mutex_lock(&data->lock);
        data->temp_tmin[attr->index] = temp;
index 84712a22acea1f4f17077cf59108701f91e07847..fe2eea4d799b60b4b4ab5df992eeb1aa200175bf 100644 (file)
@@ -953,12 +953,8 @@ static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value)
 static void asb100_init_client(struct i2c_client *client)
 {
        struct asb100_data *data = i2c_get_clientdata(client);
-       int vid = 0;
 
-       vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
-       vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
        data->vrm = vid_which_vrm();
-       vid = vid_from_reg(vid, data->vrm);
 
        /* Start monitoring */
        asb100_write_value(client, ASB100_REG_CONFIG,
index 115f4090b98e3c94cab67e058a7e1676e9b3546c..fa7696905154ca1e14444ca2a95e946470084cd4 100644 (file)
@@ -248,7 +248,7 @@ static int lm75_detach_client(struct i2c_client *client)
 
 /* All registers are word-sized, except for the configuration register.
    LM75 uses a high-byte first convention, which is exactly opposite to
-   the usual practice. */
+   the SMBus standard. */
 static int lm75_read_value(struct i2c_client *client, u8 reg)
 {
        if (reg == LM75_REG_CONF)
@@ -257,9 +257,6 @@ static int lm75_read_value(struct i2c_client *client, u8 reg)
                return swab16(i2c_smbus_read_word_data(client, reg));
 }
 
-/* All registers are word-sized, except for the configuration register.
-   LM75 uses a high-byte first convention, which is exactly opposite to
-   the usual practice. */
 static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
 {
        if (reg == LM75_REG_CONF)
index f61d8f4185b243efcf7bd3fb0f10fa6284dde6d2..eb03544c731ca47dd94c6d7d940b3f66a43dbcdd 100644 (file)
@@ -335,11 +335,23 @@ exit:
 static int __init smsc47b397_find(unsigned short *addr)
 {
        u8 id, rev;
+       char *name;
 
        superio_enter();
        id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
 
-       if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
+       switch(id) {
+       case 0x81:
+               name = "SCH5307-NS";
+               break;
+       case 0x6f:
+               name = "LPC47B397-NC";
+               break;
+       case 0x85:
+       case 0x8c:
+               name = "SCH5317";
+               break;
+       default:
                superio_exit();
                return -ENODEV;
        }
@@ -352,8 +364,7 @@ static int __init smsc47b397_find(unsigned short *addr)
 
        printk(KERN_INFO DRVNAME ": found SMSC %s "
                "(base address 0x%04x, revision %u)\n",
-               id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
-              "LPC47B397-NC", *addr, rev);
+               name, *addr, rev);
 
        superio_exit();
        return 0;
index ee35af93b574d37879acf53d813bd24f12c8dc29..ed3c019b78c7284f805a83596abba56f77664028 100644 (file)
@@ -1024,10 +1024,9 @@ static struct sensor_device_attribute_2 w83793_vid[] = {
        SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
        SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
 };
+static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
 
 static struct sensor_device_attribute_2 sda_single_files[] = {
-       SENSOR_ATTR_2(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm,
-                     NOT_USED, NOT_USED),
        SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
                      store_chassis_clear, ALARM_STATUS, 30),
        SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
@@ -1080,6 +1079,7 @@ static int w83793_detach_client(struct i2c_client *client)
 
                for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
                        device_remove_file(dev, &w83793_vid[i].dev_attr);
+               device_remove_file(dev, &dev_attr_vrm);
 
                for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
                        device_remove_file(dev, &w83793_left_fan[i].dev_attr);
@@ -1282,7 +1282,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
        /* Initialize the chip */
        w83793_init_client(client);
 
-       data->vrm = vid_which_vrm();
        /*
           Only fan 1-5 has their own input pins,
           Pwm 1-3 has their own pins
@@ -1293,7 +1292,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
        val = w83793_read_value(client, W83793_REG_FANIN_CTRL);
 
        /* check the function of pins 49-56 */
-       if (!(tmp & 0x80)) {
+       if (tmp & 0x80) {
+               data->has_vid |= 0x2;   /* has VIDB */
+       } else {
                data->has_pwm |= 0x18;  /* pwm 4,5 */
                if (val & 0x01) {       /* fan 6 */
                        data->has_fan |= 0x20;
@@ -1309,13 +1310,15 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
                }
        }
 
+       /* check the function of pins 37-40 */
+       if (!(tmp & 0x29))
+               data->has_vid |= 0x1;   /* has VIDA */
        if (0x08 == (tmp & 0x0c)) {
                if (val & 0x08) /* fan 9 */
                        data->has_fan |= 0x100;
                if (val & 0x10) /* fan 10 */
                        data->has_fan |= 0x200;
        }
-
        if (0x20 == (tmp & 0x30)) {
                if (val & 0x20) /* fan 11 */
                        data->has_fan |= 0x400;
@@ -1359,13 +1362,6 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
        if (tmp & 0x02)
                data->has_temp |= 0x20;
 
-       /* Detect the VID usage and ignore unused input */
-       tmp = w83793_read_value(client, W83793_REG_MFC);
-       if (!(tmp & 0x29))
-               data->has_vid |= 0x1;   /* has VIDA */
-       if (tmp & 0x80)
-               data->has_vid |= 0x2;   /* has VIDB */
-
        /* Register sysfs hooks */
        for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) {
                err = device_create_file(dev,
@@ -1381,6 +1377,12 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
                if (err)
                        goto exit_remove;
        }
+       if (data->has_vid) {
+               data->vrm = vid_which_vrm();
+               err = device_create_file(dev, &dev_attr_vrm);
+               if (err)
+                       goto exit_remove;
+       }
 
        for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
                err = device_create_file(dev, &sda_single_files[i].dev_attr);
index 77f2d482888b1fe3293080be6d83d17a17a4fd08..52e268e25dab01e574f97293008ec8e7a7e869fc 100644 (file)
@@ -301,8 +301,8 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
                msleep(i);
        }
 
-       dev_err(&client->dev, "Couldn't read value from register 0x%02x. "
-               "Please report.\n", reg);
+       dev_err(&client->dev, "Couldn't read value from register 0x%02x.\n",
+               reg);
        return defval;
 }
 
index 099a0fe1745b3c209cfc9f065b60308f643f3196..591deda3f86a9ef655560abb059aa710fdbb2418 100644 (file)
@@ -1347,7 +1347,8 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
            (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
                hwif->irq = port ? 15 : 14;
 
-       hwif->host_flags = d->host_flags;
+       /* ->host_flags may be set by ->init_iops (or even earlier...) */
+       hwif->host_flags |= d->host_flags;
        hwif->pio_mask = d->pio_mask;
 
        /* ->set_pio_mode for DTC2278 is currently limited to port 0 */
index 29d833e71cbfbc3c8ef0be7137186cc07afa553e..05710c7c12206aa1a9fcca8bad4db2eac3be7697 100644 (file)
@@ -520,8 +520,11 @@ static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
        char *scratch = buf;
 
        driver = container_of(drv, struct hpsb_protocol_driver, driver);
+       id = driver->id_table;
+       if (!id)
+               return 0;
 
-       for (id = driver->id_table; id->match_flags != 0; id++) {
+       for (; id->match_flags != 0; id++) {
                int need_coma = 0;
 
                if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
index 877be9922c3d24de4480d77dc25f017e86548092..15906d005b05de9f6371f75b6ca5b92617c0f4a3 100644 (file)
@@ -405,7 +405,8 @@ hysdn_procconf_init(void)
                sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
                if ((card->procconf = (void *) proc_create(conf_name,
                                                S_IFREG | S_IRUGO | S_IWUSR,
-                                               hysdn_proc_entry)) != NULL) {
+                                               hysdn_proc_entry,
+                                               &conf_fops)) != NULL) {
                        hysdn_proclog_init(card);       /* init the log file entry */
                }
                card = card->next;      /* next entry */
index 2bc9bf7e88e5e8f03a62347a346a1fc2cfd2c747..8080249957afb6d747631674d32cdc287319f96c 100644 (file)
@@ -85,27 +85,34 @@ static unsigned desc_size(const struct lguest_device_desc *desc)
                + desc->config_len;
 }
 
-/* This tests (and acknowleges) a feature bit. */
-static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
+/* This gets the device's feature bits. */
+static u32 lg_get_features(struct virtio_device *vdev)
 {
+       unsigned int i;
+       u32 features = 0;
        struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
-       u8 *features;
-
-       /* Obviously if they ask for a feature off the end of our feature
-        * bitmap, it's not set. */
-       if (fbit / 8 > desc->feature_len)
-               return false;
-
-       /* The feature bitmap comes after the virtqueues. */
-       features = lg_features(desc);
-       if (!(features[fbit / 8] & (1 << (fbit % 8))))
-               return false;
-
-       /* We set the matching bit in the other half of the bitmap to tell the
-        * Host we want to use this feature.  We don't use this yet, but we
-        * could in future. */
-       features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
-       return true;
+       u8 *in_features = lg_features(desc);
+
+       /* We do this the slow but generic way. */
+       for (i = 0; i < min(desc->feature_len * 8, 32); i++)
+               if (in_features[i / 8] & (1 << (i % 8)))
+                       features |= (1 << i);
+
+       return features;
+}
+
+static void lg_set_features(struct virtio_device *vdev, u32 features)
+{
+       unsigned int i;
+       struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+       /* Second half of bitmap is features we accept. */
+       u8 *out_features = lg_features(desc) + desc->feature_len;
+
+       memset(out_features, 0, desc->feature_len);
+       for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
+               if (features & (1 << i))
+                       out_features[i / 8] |= (1 << (i % 8));
+       }
 }
 
 /* Once they've found a field, getting a copy of it is easy. */
@@ -137,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev)
        return to_lgdev(vdev)->desc->status;
 }
 
+/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
+ * descriptor address of the device.  A zero status means "reset". */
+static void set_status(struct virtio_device *vdev, u8 status)
+{
+       unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
+
+       /* We set the status. */
+       to_lgdev(vdev)->desc->status = status;
+       hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+}
+
 static void lg_set_status(struct virtio_device *vdev, u8 status)
 {
        BUG_ON(!status);
-       to_lgdev(vdev)->desc->status = status;
+       set_status(vdev, status);
 }
 
-/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
- * address of the device.  The Host will zero the status and all the
- * features. */
 static void lg_reset(struct virtio_device *vdev)
 {
-       unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
-
-       hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+       set_status(vdev, 0);
 }
 
 /*
@@ -286,7 +299,8 @@ static void lg_del_vq(struct virtqueue *vq)
 
 /* The ops structure which hooks everything together. */
 static struct virtio_config_ops lguest_config_ops = {
-       .feature = lg_feature,
+       .get_features = lg_get_features,
+       .set_features = lg_set_features,
        .get = lg_get,
        .set = lg_set,
        .get_status = lg_get_status,
index 645e6e040bfbeab46bad83b52f9bdf42a310d788..e73a000473cc524cd16d9773da390047d362751e 100644 (file)
@@ -102,7 +102,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
 static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
 {
        /* We have a limited number the number of CPUs in the lguest struct. */
-       if (id >= NR_CPUS)
+       if (id >= ARRAY_SIZE(cpu->lg->cpus))
                return -EINVAL;
 
        /* Set up this CPU's id, and pointer back to the lguest struct. */
@@ -251,8 +251,6 @@ static ssize_t write(struct file *file, const char __user *in,
                if (!lg || (cpu_id >= lg->nr_cpus))
                        return -EINVAL;
                cpu = &lg->cpus[cpu_id];
-               if (!cpu)
-                       return -EINVAL;
 
                /* Once the Guest is dead, you can only read() why it died. */
                if (lg->dead)
index e812df607a5c9aef596e96c4800881cb2df15967..fcd1aeccdf9393d0780da7ff83c94d8f32e1af62 100644 (file)
@@ -82,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
 static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
 
 static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
-                    size_t *retlen, u_char **mtdbuf);
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
-                       size_t len);
+                    size_t *retlen, void **virt, resource_size_t *phys);
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
 
 static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
@@ -1240,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
        return ret;
 }
 
-static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, void **virt, resource_size_t *phys)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
@@ -1257,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
        chipnum = (from >> cfi->chipshift);
        ofs = from - (chipnum << cfi->chipshift);
 
-       *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+       *virt = map->virt + cfi->chips[chipnum].start + ofs;
        *retlen = 0;
+       if (phys)
+               *phys = map->phys + cfi->chips[chipnum].start + ofs;
 
        while (len) {
                unsigned long thislen;
@@ -1291,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
        return 0;
 }
 
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
index bf485ff49457303cc3307655d266085ff23ea098..0399be178620ab67be22917e12595118fc3211f0 100644 (file)
@@ -48,18 +48,21 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
 }
 
 static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
-               size_t *retlen, u_char **mtdbuf)
+               size_t *retlen, void **virt, resource_size_t *phys)
 {
        if (from + len > mtd->size)
                return -EINVAL;
 
-       *mtdbuf = mtd->priv + from;
+       /* can we return a physical address with this driver? */
+       if (phys)
+               return -EINVAL;
+
+       *virt = mtd->priv + from;
        *retlen = len;
        return 0;
 }
 
-static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
-               size_t len)
+static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
 }
 
index 5f960182da957eaa8c4a12295fe93b66677e4287..c7987b1c5e01db083f237fa26b1c48d963a77a7d 100644 (file)
@@ -57,20 +57,21 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
 }
 
 static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
-               size_t *retlen, u_char **mtdbuf)
+               size_t *retlen, void **virt, resource_size_t *phys)
 {
-       u_char *start = mtd->priv;
-
        if (from + len > mtd->size)
                return -EINVAL;
 
-       *mtdbuf = start + from;
+       /* can we return a physical address with this driver? */
+       if (phys)
+               return -EINVAL;
+
+       *virt = mtd->priv + from;
        *retlen = len;
        return 0;
 }
 
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
-               size_t len)
+static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
 }
 
index 7060a0895ce26fd95bf67f2cdc85418bfbc0078e..bc99817490649572ced4f09e01ec2606c252a854 100644 (file)
@@ -134,7 +134,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
        eoff_lo = end & (priv->asize - 1);
        soff_lo = instr->addr & (priv->asize - 1);
 
-       pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr);
+       pmc551_point(mtd, instr->addr, instr->len, &retlen,
+                    (void **)&ptr, NULL);
 
        if (soff_hi == eoff_hi || mtd->size == priv->asize) {
                /* The whole thing fits within one access, so just one shot
@@ -154,7 +155,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
                        }
                        soff_hi += priv->asize;
                        pmc551_point(mtd, (priv->base_map0 | soff_hi),
-                                    priv->asize, &retlen, &ptr);
+                                    priv->asize, &retlen,
+                                    (void **)&ptr, NULL);
                }
                memset(ptr, 0xff, eoff_lo);
        }
@@ -170,7 +172,7 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
 }
 
 static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t * retlen, u_char ** mtdbuf)
+                       size_t *retlen, void **virt, resource_size_t *phys)
 {
        struct mypriv *priv = mtd->priv;
        u32 soff_hi;
@@ -188,6 +190,10 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
                return -EINVAL;
        }
 
+       /* can we return a physical address with this driver? */
+       if (phys)
+               return -EINVAL;
+
        soff_hi = from & ~(priv->asize - 1);
        soff_lo = from & (priv->asize - 1);
 
@@ -198,13 +204,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
                priv->curr_map0 = soff_hi;
        }
 
-       *mtdbuf = priv->start + soff_lo;
+       *virt = priv->start + soff_lo;
        *retlen = len;
        return 0;
 }
 
-static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
-                          size_t len)
+static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
 #ifdef CONFIG_MTD_PMC551_DEBUG
        printk(KERN_DEBUG "pmc551_unpoint()\n");
@@ -242,7 +247,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
        soff_lo = from & (priv->asize - 1);
        eoff_lo = end & (priv->asize - 1);
 
-       pmc551_point(mtd, from, len, retlen, &ptr);
+       pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL);
 
        if (soff_hi == eoff_hi) {
                /* The whole thing fits within one access, so just one shot
@@ -263,7 +268,8 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
                                goto out;
                        }
                        soff_hi += priv->asize;
-                       pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+                       pmc551_point(mtd, soff_hi, priv->asize, retlen,
+                                    (void **)&ptr, NULL);
                }
                memcpy(copyto, ptr, eoff_lo);
                copyto += eoff_lo;
@@ -308,7 +314,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
        soff_lo = to & (priv->asize - 1);
        eoff_lo = end & (priv->asize - 1);
 
-       pmc551_point(mtd, to, len, retlen, &ptr);
+       pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL);
 
        if (soff_hi == eoff_hi) {
                /* The whole thing fits within one access, so just one shot
@@ -329,7 +335,8 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
                                goto out;
                        }
                        soff_hi += priv->asize;
-                       pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+                       pmc551_point(mtd, soff_hi, priv->asize, retlen,
+                                    (void **)&ptr, NULL);
                }
                memcpy(ptr, copyfrom, eoff_lo);
                copyfrom += eoff_lo;
index d293add1857cfba358a033ff0247e7c755ef42c1..cb86db746f28c91f552462696b10d5c99f23c07d 100644 (file)
@@ -76,8 +76,9 @@ static char *map;
 static slram_mtd_list_t *slram_mtdlist = NULL;
 
 static int slram_erase(struct mtd_info *, struct erase_info *);
-static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
+static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
+               resource_size_t *);
+static void slram_unpoint(struct mtd_info *, loff_t, size_t);
 static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
@@ -104,19 +105,23 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
 }
 
 static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
-               size_t *retlen, u_char **mtdbuf)
+               size_t *retlen, void **virt, resource_size_t *phys)
 {
        slram_priv_t *priv = mtd->priv;
 
+       /* can we return a physical address with this driver? */
+       if (phys)
+               return -EINVAL;
+
        if (from + len > mtd->size)
                return -EINVAL;
 
-       *mtdbuf = priv->start + from;
+       *virt = priv->start + from;
        *retlen = len;
        return(0);
 }
 
-static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
 }
 
index 14ffb1a9302a51e8dc2271f7311116b1f7b635f3..c42f4b83f686dc0235f699b75a2dd457f4f53218 100644 (file)
@@ -40,10 +40,12 @@ struct mtd_partition uclinux_romfs[] = {
 /****************************************************************************/
 
 int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char **mtdbuf)
+       size_t *retlen, void **virt, resource_size_t *phys)
 {
        struct map_info *map = mtd->priv;
-       *mtdbuf = (u_char *) (map->virt + ((int) from));
+       *virt = map->virt + from;
+       if (phys)
+               *phys = map->phys + from;
        *retlen = len;
        return(0);
 }
index c66902df3171aef08e1066fde0157992f456ffdc..07c701169344266e907ce92ee2068c2a8ad6881d 100644 (file)
@@ -68,7 +68,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
 }
 
 static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char **buf)
+                       size_t *retlen, void **virt, resource_size_t *phys)
 {
        struct mtd_part *part = PART(mtd);
        if (from >= mtd->size)
@@ -76,14 +76,14 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
        else if (from + len > mtd->size)
                len = mtd->size - from;
        return part->master->point (part->master, from + part->offset,
-                                   len, retlen, buf);
+                                   len, retlen, virt, phys);
 }
 
-static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
        struct mtd_part *part = PART(mtd);
 
-       part->master->unpoint (part->master, addr, from + part->offset, len);
+       part->master->unpoint(part->master, from + part->offset, len);
 }
 
 static int part_read_oob(struct mtd_info *mtd, loff_t from,
index 414ceaecdb3a2058bbba13def192553ed40ce29f..0adb287027a249409062c5ba6a46cadc717f50a8 100644 (file)
@@ -93,6 +93,24 @@ struct at91_nand_host {
        void __iomem            *ecc;
 };
 
+/*
+ * Enable NAND.
+ */
+static void at91_nand_enable(struct at91_nand_host *host)
+{
+       if (host->board->enable_pin)
+               at91_set_gpio_value(host->board->enable_pin, 0);
+}
+
+/*
+ * Disable NAND.
+ */
+static void at91_nand_disable(struct at91_nand_host *host)
+{
+       if (host->board->enable_pin)
+               at91_set_gpio_value(host->board->enable_pin, 1);
+}
+
 /*
  * Hardware specific access to control-lines
  */
@@ -101,11 +119,11 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        struct nand_chip *nand_chip = mtd->priv;
        struct at91_nand_host *host = nand_chip->priv;
 
-       if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) {
+       if (ctrl & NAND_CTRL_CHANGE) {
                if (ctrl & NAND_NCE)
-                       at91_set_gpio_value(host->board->enable_pin, 0);
+                       at91_nand_enable(host);
                else
-                       at91_set_gpio_value(host->board->enable_pin, 1);
+                       at91_nand_disable(host);
        }
        if (cmd == NAND_CMD_NONE)
                return;
@@ -127,24 +145,6 @@ static int at91_nand_device_ready(struct mtd_info *mtd)
        return at91_get_gpio_value(host->board->rdy_pin);
 }
 
-/*
- * Enable NAND.
- */
-static void at91_nand_enable(struct at91_nand_host *host)
-{
-       if (host->board->enable_pin)
-               at91_set_gpio_value(host->board->enable_pin, 0);
-}
-
-/*
- * Disable NAND.
- */
-static void at91_nand_disable(struct at91_nand_host *host)
-{
-       if (host->board->enable_pin)
-               at91_set_gpio_value(host->board->enable_pin, 1);
-}
-
 /*
  * write oob for small pages
  */
index d7a3ea88eddb562be4f632387d30776da84f4ef7..32a4f17d35fc5f1387ca232bc7100761cc7bcafe 100644 (file)
 #define        FEC_MAX_PORTS   1
 #endif
 
+#if defined(CONFIG_FADS) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_M5272)
+#define HAVE_mii_link_interrupt
+#endif
+
 /*
  * Define the fixed address of the FEC hardware.
  */
@@ -205,7 +209,10 @@ struct fec_enet_private {
        cbd_t   *cur_rx, *cur_tx;               /* The next free ring entry */
        cbd_t   *dirty_tx;      /* The ring entries to be free()ed. */
        uint    tx_full;
-       spinlock_t lock;
+       /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
+       spinlock_t hw_lock;
+       /* hold while accessing the mii_list_t() elements */
+       spinlock_t mii_lock;
 
        uint    phy_id;
        uint    phy_id_done;
@@ -309,6 +316,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        volatile fec_t  *fecp;
        volatile cbd_t  *bdp;
        unsigned short  status;
+       unsigned long flags;
 
        fep = netdev_priv(dev);
        fecp = (volatile fec_t*)dev->base_addr;
@@ -318,6 +326,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
                return 1;
        }
 
+       spin_lock_irqsave(&fep->hw_lock, flags);
        /* Fill in a Tx ring entry */
        bdp = fep->cur_tx;
 
@@ -328,6 +337,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 * This should not happen, since dev->tbusy should be set.
                 */
                printk("%s: tx queue full!.\n", dev->name);
+               spin_unlock_irqrestore(&fep->hw_lock, flags);
                return 1;
        }
 #endif
@@ -366,8 +376,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        flush_dcache_range((unsigned long)skb->data,
                           (unsigned long)skb->data + skb->len);
 
-       spin_lock_irq(&fep->lock);
-
        /* Send it on its way.  Tell FEC it's ready, interrupt when done,
         * it's the last BD of the frame, and to put the CRC on the end.
         */
@@ -396,7 +404,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        fep->cur_tx = (cbd_t *)bdp;
 
-       spin_unlock_irq(&fep->lock);
+       spin_unlock_irqrestore(&fep->hw_lock, flags);
 
        return 0;
 }
@@ -454,19 +462,20 @@ fec_enet_interrupt(int irq, void * dev_id)
        struct  net_device *dev = dev_id;
        volatile fec_t  *fecp;
        uint    int_events;
-       int handled = 0;
+       irqreturn_t ret = IRQ_NONE;
 
        fecp = (volatile fec_t*)dev->base_addr;
 
        /* Get the interrupt events that caused us to be here.
        */
-       while ((int_events = fecp->fec_ievent) != 0) {
+       do {
+               int_events = fecp->fec_ievent;
                fecp->fec_ievent = int_events;
 
                /* Handle receive event in its own function.
                 */
                if (int_events & FEC_ENET_RXF) {
-                       handled = 1;
+                       ret = IRQ_HANDLED;
                        fec_enet_rx(dev);
                }
 
@@ -475,17 +484,18 @@ fec_enet_interrupt(int irq, void * dev_id)
                   them as part of the transmit process.
                */
                if (int_events & FEC_ENET_TXF) {
-                       handled = 1;
+                       ret = IRQ_HANDLED;
                        fec_enet_tx(dev);
                }
 
                if (int_events & FEC_ENET_MII) {
-                       handled = 1;
+                       ret = IRQ_HANDLED;
                        fec_enet_mii(dev);
                }
 
-       }
-       return IRQ_RETVAL(handled);
+       } while (int_events);
+
+       return ret;
 }
 
 
@@ -498,7 +508,7 @@ fec_enet_tx(struct net_device *dev)
        struct  sk_buff *skb;
 
        fep = netdev_priv(dev);
-       spin_lock(&fep->lock);
+       spin_lock_irq(&fep->hw_lock);
        bdp = fep->dirty_tx;
 
        while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
@@ -557,7 +567,7 @@ fec_enet_tx(struct net_device *dev)
                }
        }
        fep->dirty_tx = (cbd_t *)bdp;
-       spin_unlock(&fep->lock);
+       spin_unlock_irq(&fep->hw_lock);
 }
 
 
@@ -584,6 +594,8 @@ fec_enet_rx(struct net_device *dev)
        fep = netdev_priv(dev);
        fecp = (volatile fec_t*)dev->base_addr;
 
+       spin_lock_irq(&fep->hw_lock);
+
        /* First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
         */
@@ -689,6 +701,8 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
         */
        fecp->fec_r_des_active = 0;
 #endif
+
+       spin_unlock_irq(&fep->hw_lock);
 }
 
 
@@ -702,11 +716,11 @@ fec_enet_mii(struct net_device *dev)
        uint            mii_reg;
 
        fep = netdev_priv(dev);
+       spin_lock_irq(&fep->mii_lock);
+
        ep = fep->hwp;
        mii_reg = ep->fec_mii_data;
 
-       spin_lock(&fep->lock);
-
        if ((mip = mii_head) == NULL) {
                printk("MII and no head!\n");
                goto unlock;
@@ -723,7 +737,7 @@ fec_enet_mii(struct net_device *dev)
                ep->fec_mii_data = mip->mii_regval;
 
 unlock:
-       spin_unlock(&fep->lock);
+       spin_unlock_irq(&fep->mii_lock);
 }
 
 static int
@@ -737,12 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
        /* Add PHY address to register command.
        */
        fep = netdev_priv(dev);
-       regval |= fep->phy_addr << 23;
+       spin_lock_irqsave(&fep->mii_lock, flags);
 
+       regval |= fep->phy_addr << 23;
        retval = 0;
 
-       spin_lock_irqsave(&fep->lock,flags);
-
        if ((mip = mii_free) != NULL) {
                mii_free = mip->mii_next;
                mip->mii_regval = regval;
@@ -759,9 +772,8 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
                retval = 1;
        }
 
-       spin_unlock_irqrestore(&fep->lock,flags);
-
-       return(retval);
+       spin_unlock_irqrestore(&fep->mii_lock, flags);
+       return retval;
 }
 
 static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
@@ -1222,7 +1234,7 @@ static phy_info_t const * const phy_info[] = {
 };
 
 /* ------------------------------------------------------------------------- */
-#if !defined(CONFIG_M532x)
+#ifdef HAVE_mii_link_interrupt
 #ifdef CONFIG_RPXCLASSIC
 static void
 mii_link_interrupt(void *dev_id);
@@ -1362,18 +1374,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
                unsigned short irq;
        } *idp, id[] = {
                { "fec(TXF)", 23 },
-               { "fec(TXB)", 24 },
-               { "fec(TXFIFO)", 25 },
-               { "fec(TXCR)", 26 },
                { "fec(RXF)", 27 },
-               { "fec(RXB)", 28 },
                { "fec(MII)", 29 },
-               { "fec(LC)", 30 },
-               { "fec(HBERR)", 31 },
-               { "fec(GRA)", 32 },
-               { "fec(EBERR)", 33 },
-               { "fec(BABT)", 34 },
-               { "fec(BABR)", 35 },
                { NULL },
        };
 
@@ -1533,18 +1535,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
                unsigned short irq;
        } *idp, id[] = {
                { "fec(TXF)", 23 },
-               { "fec(TXB)", 24 },
-               { "fec(TXFIFO)", 25 },
-               { "fec(TXCR)", 26 },
                { "fec(RXF)", 27 },
-               { "fec(RXB)", 28 },
                { "fec(MII)", 29 },
-               { "fec(LC)", 30 },
-               { "fec(HBERR)", 31 },
-               { "fec(GRA)", 32 },
-               { "fec(EBERR)", 33 },
-               { "fec(BABT)", 34 },
-               { "fec(BABR)", 35 },
                { NULL },
        };
 
@@ -1660,18 +1652,8 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
                unsigned short irq;
        } *idp, id[] = {
            { "fec(TXF)", 36 },
-           { "fec(TXB)", 37 },
-           { "fec(TXFIFO)", 38 },
-           { "fec(TXCR)", 39 },
            { "fec(RXF)", 40 },
-           { "fec(RXB)", 41 },
            { "fec(MII)", 42 },
-           { "fec(LC)", 43 },
-           { "fec(HBERR)", 44 },
-           { "fec(GRA)", 45 },
-           { "fec(EBERR)", 46 },
-           { "fec(BABT)", 47 },
-           { "fec(BABR)", 48 },
            { NULL },
        };
 
@@ -2126,6 +2108,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
 
 /* This interrupt occurs when the PHY detects a link change.
 */
+#ifdef HAVE_mii_link_interrupt
 #ifdef CONFIG_RPXCLASSIC
 static void
 mii_link_interrupt(void *dev_id)
@@ -2148,6 +2131,7 @@ mii_link_interrupt(int irq, void * dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static int
 fec_enet_open(struct net_device *dev)
@@ -2243,13 +2227,13 @@ static void set_multicast_list(struct net_device *dev)
                        /* Catch all multicast addresses, so set the
                         * filter to all 1's.
                         */
-                       ep->fec_hash_table_high = 0xffffffff;
-                       ep->fec_hash_table_low = 0xffffffff;
+                       ep->fec_grp_hash_table_high = 0xffffffff;
+                       ep->fec_grp_hash_table_low = 0xffffffff;
                } else {
                        /* Clear filter and add the addresses in hash register.
                        */
-                       ep->fec_hash_table_high = 0;
-                       ep->fec_hash_table_low = 0;
+                       ep->fec_grp_hash_table_high = 0;
+                       ep->fec_grp_hash_table_low = 0;
 
                        dmi = dev->mc_list;
 
@@ -2280,9 +2264,9 @@ static void set_multicast_list(struct net_device *dev)
                                hash = (crc >> (32 - HASH_BITS)) & 0x3f;
 
                                if (hash > 31)
-                                       ep->fec_hash_table_high |= 1 << (hash - 32);
+                                       ep->fec_grp_hash_table_high |= 1 << (hash - 32);
                                else
-                                       ep->fec_hash_table_low |= 1 << hash;
+                                       ep->fec_grp_hash_table_low |= 1 << hash;
                        }
                }
        }
@@ -2332,6 +2316,9 @@ int __init fec_enet_init(struct net_device *dev)
                return -ENOMEM;
        }
 
+       spin_lock_init(&fep->hw_lock);
+       spin_lock_init(&fep->mii_lock);
+
        /* Create an Ethernet device instance.
        */
        fecp = (volatile fec_t *) fec_hw[index];
@@ -2430,11 +2417,15 @@ int __init fec_enet_init(struct net_device *dev)
        */
        fec_request_intrs(dev);
 
-       fecp->fec_hash_table_high = 0;
-       fecp->fec_hash_table_low = 0;
+       fecp->fec_grp_hash_table_high = 0;
+       fecp->fec_grp_hash_table_low = 0;
        fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
        fecp->fec_ecntrl = 2;
        fecp->fec_r_des_active = 0;
+#ifndef CONFIG_M5272
+       fecp->fec_hash_table_high = 0;
+       fecp->fec_hash_table_low = 0;
+#endif
 
        dev->base_addr = (unsigned long)fecp;
 
@@ -2455,8 +2446,7 @@ int __init fec_enet_init(struct net_device *dev)
 
        /* Clear and enable interrupts */
        fecp->fec_ievent = 0xffc00000;
-       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
 
        /* Queue up command to detect the PHY and initialize the
         * remainder of the interface.
@@ -2500,8 +2490,8 @@ fec_restart(struct net_device *dev, int duplex)
 
        /* Reset all multicast.
        */
-       fecp->fec_hash_table_high = 0;
-       fecp->fec_hash_table_low = 0;
+       fecp->fec_grp_hash_table_high = 0;
+       fecp->fec_grp_hash_table_low = 0;
 
        /* Set maximum receive buffer size.
        */
@@ -2583,8 +2573,7 @@ fec_restart(struct net_device *dev, int duplex)
 
        /* Enable interrupts we wish to service.
        */
-       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-               FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+       fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
 }
 
 static void
@@ -2624,7 +2613,7 @@ fec_stop(struct net_device *dev)
 static int __init fec_enet_module_init(void)
 {
        struct net_device *dev;
-       int i, j, err;
+       int i, err;
        DECLARE_MAC_BUF(mac);
 
        printk("FEC ENET Version 0.2\n");
index 1d421606984fd4925e0a058ffb6bbc57e1332b06..292719daceff0e8060aa7ae6ddef7fda0a0bcf31 100644 (file)
@@ -88,8 +88,8 @@ typedef struct fec {
        unsigned long   fec_reserved7[158];
        unsigned long   fec_addr_low;           /* Low 32bits MAC address */
        unsigned long   fec_addr_high;          /* High 16bits MAC address */
-       unsigned long   fec_hash_table_high;    /* High 32bits hash table */
-       unsigned long   fec_hash_table_low;     /* Low 32bits hash table */
+       unsigned long   fec_grp_hash_table_high;/* High 32bits hash table */
+       unsigned long   fec_grp_hash_table_low; /* Low 32bits hash table */
        unsigned long   fec_r_des_start;        /* Receive descriptor ring */
        unsigned long   fec_x_des_start;        /* Transmit descriptor ring */
        unsigned long   fec_r_buff_size;        /* Maximum receive buff size */
index 555b70c8b8635226a1fa295c7334d5d70c34f939..f926b5ab3d09291f2146ebd3928bc385503fb04e 100644 (file)
@@ -41,6 +41,9 @@ struct virtnet_info
        struct net_device *dev;
        struct napi_struct napi;
 
+       /* The skb we couldn't send because buffers were full. */
+       struct sk_buff *last_xmit_skb;
+
        /* Number of input buffers, and max we've ever had. */
        unsigned int num, max;
 
@@ -142,10 +145,10 @@ drop:
 static void try_fill_recv(struct virtnet_info *vi)
 {
        struct sk_buff *skb;
-       struct scatterlist sg[1+MAX_SKB_FRAGS];
+       struct scatterlist sg[2+MAX_SKB_FRAGS];
        int num, err;
 
-       sg_init_table(sg, 1+MAX_SKB_FRAGS);
+       sg_init_table(sg, 2+MAX_SKB_FRAGS);
        for (;;) {
                skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
                if (unlikely(!skb))
@@ -221,23 +224,22 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)
        while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
                pr_debug("Sent skb %p\n", skb);
                __skb_unlink(skb, &vi->send);
-               vi->dev->stats.tx_bytes += len;
+               vi->dev->stats.tx_bytes += skb->len;
                vi->dev->stats.tx_packets++;
                kfree_skb(skb);
        }
 }
 
-static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 {
-       struct virtnet_info *vi = netdev_priv(dev);
-       int num, err;
-       struct scatterlist sg[1+MAX_SKB_FRAGS];
+       int num;
+       struct scatterlist sg[2+MAX_SKB_FRAGS];
        struct virtio_net_hdr *hdr;
        const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 
-       sg_init_table(sg, 1+MAX_SKB_FRAGS);
+       sg_init_table(sg, 2+MAX_SKB_FRAGS);
 
-       pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb,
+       pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb,
                 dest[0], dest[1], dest[2],
                 dest[3], dest[4], dest[5]);
 
@@ -272,30 +274,51 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        vnet_hdr_to_sg(sg, skb);
        num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
-       __skb_queue_head(&vi->send, skb);
+
+       return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+}
+
+static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
 
 again:
        /* Free up any pending old buffers before queueing new ones. */
        free_old_xmit_skbs(vi);
-       err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
-       if (err) {
-               pr_debug("%s: virtio not prepared to send\n", dev->name);
-               netif_stop_queue(dev);
-
-               /* Activate callback for using skbs: if this returns false it
-                * means some were used in the meantime. */
-               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
-                       vi->svq->vq_ops->disable_cb(vi->svq);
-                       netif_start_queue(dev);
-                       goto again;
+
+       /* If we has a buffer left over from last time, send it now. */
+       if (vi->last_xmit_skb) {
+               if (xmit_skb(vi, vi->last_xmit_skb) != 0) {
+                       /* Drop this skb: we only queue one. */
+                       vi->dev->stats.tx_dropped++;
+                       kfree_skb(skb);
+                       goto stop_queue;
                }
-               __skb_unlink(skb, &vi->send);
+               vi->last_xmit_skb = NULL;
+       }
 
-               return NETDEV_TX_BUSY;
+       /* Put new one in send queue and do transmit */
+       __skb_queue_head(&vi->send, skb);
+       if (xmit_skb(vi, skb) != 0) {
+               vi->last_xmit_skb = skb;
+               goto stop_queue;
        }
+done:
        vi->svq->vq_ops->kick(vi->svq);
-
-       return 0;
+       return NETDEV_TX_OK;
+
+stop_queue:
+       pr_debug("%s: virtio not prepared to send\n", dev->name);
+       netif_stop_queue(dev);
+
+       /* Activate callback for using skbs: if this returns false it
+        * means some were used in the meantime. */
+       if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+               vi->svq->vq_ops->disable_cb(vi->svq);
+               netif_start_queue(dev);
+               goto again;
+       }
+       goto done;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -355,17 +378,26 @@ static int virtnet_probe(struct virtio_device *vdev)
        SET_NETDEV_DEV(dev, &vdev->dev);
 
        /* Do we support "hardware" checksums? */
-       if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
+       if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
                /* This opens up the world of extra features. */
                dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
-               if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
+               if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
                        dev->features |= NETIF_F_TSO | NETIF_F_UFO
                                | NETIF_F_TSO_ECN | NETIF_F_TSO6;
                }
+               /* Individual feature bits: what can host handle? */
+               if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
+                       dev->features |= NETIF_F_TSO;
+               if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
+                       dev->features |= NETIF_F_TSO6;
+               if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
+                       dev->features |= NETIF_F_TSO_ECN;
+               if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
+                       dev->features |= NETIF_F_UFO;
        }
 
        /* Configuration may specify what MAC to use.  Otherwise random. */
-       if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
+       if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
                vdev->config->get(vdev,
                                  offsetof(struct virtio_net_config, mac),
                                  dev->dev_addr, dev->addr_len);
@@ -454,7 +486,15 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
+static unsigned int features[] = {
+       VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
+       VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
+       VIRTIO_NET_F_HOST_ECN,
+};
+
 static struct virtio_driver virtio_net = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
index 74e051535d6c0419cad92901dabb9c0737929deb..c78d77fd7e3bcea2a7a448c979130be99f609f0e 100644 (file)
@@ -194,7 +194,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
                                default:
                                        pwr |= SET_VCC_VPP(0,0,sock);
                                        printk("%s: bad Vcc/Vpp (%d:%d)\n",
-                                                       __FUNCTION__,
+                                                       __func__,
                                                        state->Vcc,
                                                        state->Vpp);
                                        break;
@@ -215,7 +215,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
                                default:
                                        pwr |= SET_VCC_VPP(0,0,sock);
                                        printk("%s: bad Vcc/Vpp (%d:%d)\n",
-                                                       __FUNCTION__,
+                                                       __func__,
                                                        state->Vcc,
                                                        state->Vpp);
                                        break;
@@ -224,7 +224,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
                default: /* what's this ? */
                        pwr |= SET_VCC_VPP(0,0,sock);
                        printk(KERN_ERR "%s: bad Vcc %d\n",
-                                       __FUNCTION__, state->Vcc);
+                                       __func__, state->Vcc);
                        break;
        }
 
index b693367d38cdbb3d907e14b1dd8275fed044ffe3..75e8f8505e47230156103ccb784a606ed43b8698 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/notifier.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
@@ -71,7 +72,7 @@ extern struct au1000_pcmcia_socket au1000_pcmcia_socket[];
 u32 *pcmcia_base_vaddrs[2];
 extern const unsigned long mips_io_port_base;
 
-DECLARE_MUTEX(pcmcia_sockets_lock);
+static DEFINE_MUTEX(pcmcia_sockets_lock);
 
 static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = {
        au1x_board_init,
@@ -472,7 +473,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev)
        struct skt_dev_info *sinfo = dev_get_drvdata(dev);
        int i;
 
-       down(&pcmcia_sockets_lock);
+       mutex_lock(&pcmcia_sockets_lock);
        dev_set_drvdata(dev, NULL);
 
        for (i = 0; i < sinfo->nskt; i++) {
@@ -488,7 +489,7 @@ int au1x00_drv_pcmcia_remove(struct device *dev)
        }
 
        kfree(sinfo);
-       up(&pcmcia_sockets_lock);
+       mutex_unlock(&pcmcia_sockets_lock);
        return 0;
 }
 
@@ -501,13 +502,13 @@ static int au1x00_drv_pcmcia_probe(struct device *dev)
 {
        int i, ret = -ENODEV;
 
-       down(&pcmcia_sockets_lock);
+       mutex_lock(&pcmcia_sockets_lock);
        for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) {
                ret = au1x00_pcmcia_hw_init[i](dev);
                if (ret == 0)
                        break;
        }
-       up(&pcmcia_sockets_lock);
+       mutex_unlock(&pcmcia_sockets_lock);
        return ret;
 }
 
index 86c0808d6a057920bfe07412cf1e73c9efff7c2a..157e41423a0a5390e42bb5106eccc5be489fb16f 100644 (file)
@@ -244,7 +244,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
                                        pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
                                                        configure->sock);
                                        printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __FUNCTION__, 
+                                                       __func__,
                                                        configure->vcc, 
                                                        configure->vpp);
                                        break;
@@ -272,7 +272,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
                                        pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
                                                        configure->sock);
                                        printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __FUNCTION__, 
+                                                       __func__,
                                                        configure->vcc, 
                                                        configure->vpp);
                                        break;
@@ -300,7 +300,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
                                        pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
                                                        configure->sock);
                                        printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __FUNCTION__, 
+                                                       __func__,
                                                        configure->vcc, 
                                                        configure->vpp);
                                        break;
@@ -309,7 +309,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
                default: /* what's this ? */
                        pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
                        printk(KERN_ERR "%s: bad Vcc %d\n", 
-                                       __FUNCTION__, configure->vcc);
+                                       __func__, configure->vcc);
                        break;
        }
 
@@ -353,7 +353,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
                                default:
                                        pcr |= SET_VCC_VPP(0,0);
                                        printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __FUNCTION__, 
+                                                       __func__,
                                                        configure->vcc, 
                                                        configure->vpp);
                                        break;
@@ -374,7 +374,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
                                default:
                                        pcr |= SET_VCC_VPP(0,0);
                                        printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-                                                       __FUNCTION__, 
+                                                       __func__,
                                                        configure->vcc, 
                                                        configure->vpp);
                                        break;
@@ -383,7 +383,7 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
                default: /* what's this ? */
                        pcr |= SET_VCC_VPP(0,0);
                        printk(KERN_ERR "%s: bad Vcc %d\n", 
-                                       __FUNCTION__, configure->vcc);
+                                       __func__, configure->vcc);
                        break;
        }
 
index ce9d5c44a7b5a8253dc8d553f20b9a246cf38830..c78ed53475107c7371b503aa68c6d6ff96c6c4e6 100644 (file)
@@ -56,7 +56,7 @@
 #define PCMCIA_IRQ             AU1000_GPIO_4
 
 #if 0
-#define DEBUG(x,args...)       printk(__FUNCTION__ ": " x,##args)
+#define DEBUG(x, args...)      printk(__func__ ": " x, ##args)
 #else
 #define DEBUG(x,args...)
 #endif
index 714baaeb6da1257a264c903b4b36d67570c15486..fb2f38dc92c560de378ddab5b688657e82d8661a 100644 (file)
@@ -209,7 +209,7 @@ static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
        }
 }
 
-int cb_alloc(struct pcmcia_socket * s)
+int __ref cb_alloc(struct pcmcia_socket * s)
 {
        struct pci_bus *bus = s->cb_dev->subordinate;
        struct pci_dev *dev;
index 56230dbd347aee88f9d6eb9fc1a32ec9642d7799..29276bd28295007212a73e89c4bc44cb6f0a0a2a 100644 (file)
@@ -652,6 +652,9 @@ static int pccardd(void *__skt)
                complete(&skt->thread_done);
                return 0;
        }
+       ret = pccard_sysfs_add_socket(&skt->dev);
+       if (ret)
+               dev_warn(&skt->dev, "err %d adding socket attributes\n", ret);
 
        add_wait_queue(&skt->thread_wait, &wait);
        complete(&skt->thread_done);
@@ -694,6 +697,7 @@ static int pccardd(void *__skt)
        remove_wait_queue(&skt->thread_wait, &wait);
 
        /* remove from the device core */
+       pccard_sysfs_remove_socket(&skt->dev);
        device_unregister(&skt->dev);
 
        return 0;
@@ -940,20 +944,13 @@ EXPORT_SYMBOL(pcmcia_socket_class);
 
 static int __init init_pcmcia_cs(void)
 {
-       int ret;
-
        init_completion(&pcmcia_unload);
-       ret = class_register(&pcmcia_socket_class);
-       if (ret)
-               return (ret);
-       return class_interface_register(&pccard_sysfs_interface);
+       return class_register(&pcmcia_socket_class);
 }
 
 static void __exit exit_pcmcia_cs(void)
 {
-       class_interface_unregister(&pccard_sysfs_interface);
        class_unregister(&pcmcia_socket_class);
-
        wait_for_completion(&pcmcia_unload);
 }
 
index 9fa207e3c7b35757dcd394cb1478191b266d3ed6..e7d5d141f24dc9b661f9ed4412752c53a04b7764 100644 (file)
@@ -121,7 +121,8 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
 void release_resource_db(struct pcmcia_socket *s);
 
 /* In socket_sysfs.c */
-extern struct class_interface pccard_sysfs_interface;
+extern int pccard_sysfs_add_socket(struct device *dev);
+extern void pccard_sysfs_remove_socket(struct device *dev);
 
 /* In cs.c */
 extern struct rw_semaphore pcmcia_socket_list_rwsem;
index 5a85871f5ee919ff3bdb18f10be8715132b037de..e40775443d04c73233735c61b0802eaa4936a751 100644 (file)
@@ -1520,7 +1520,7 @@ static void pcmcia_bus_remove_socket(struct device *dev,
 
 
 /* the pcmcia_bus_interface is used to handle pcmcia socket devices */
-static struct class_interface pcmcia_bus_interface = {
+static struct class_interface pcmcia_bus_interface __refdata = {
        .class = &pcmcia_socket_class,
        .add_dev = &pcmcia_bus_add_socket,
        .remove_dev = &pcmcia_bus_remove_socket,
index e54ecc580d9ed328cc887cb843ab58542d5f5b34..e13618656ff7ee7807618c9a52e0398334e04505 100644 (file)
@@ -53,7 +53,7 @@ static int i82092aa_socket_resume (struct pci_dev *dev)
 }
 #endif
 
-static struct pci_driver i82092aa_pci_drv = {
+static struct pci_driver i82092aa_pci_driver = {
        .name           = "i82092aa",
        .id_table       = i82092aa_pci_ids,
        .probe          = i82092aa_pci_probe,
@@ -714,13 +714,13 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
 
 static int i82092aa_module_init(void)
 {
-       return pci_register_driver(&i82092aa_pci_drv);
+       return pci_register_driver(&i82092aa_pci_driver);
 }
 
 static void i82092aa_module_exit(void)
 {
        enter("i82092aa_module_exit");
-       pci_unregister_driver(&i82092aa_pci_drv);
+       pci_unregister_driver(&i82092aa_pci_driver);
        if (sockets[0].io_base>0)
                         release_region(sockets[0].io_base, 2);
        leave("i82092aa_module_exit");
index bb6db3a582b2292d1dbe7777e87c545a4b00d737..46314b420765e6dffc63d3a5f4ce31241e3bccf6 100644 (file)
@@ -153,7 +153,7 @@ omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
 
 static int omap_cf_ss_suspend(struct pcmcia_socket *s)
 {
-       pr_debug("%s: %s\n", driver_name, __FUNCTION__);
+       pr_debug("%s: %s\n", driver_name, __func__);
        return omap_cf_set_socket(s, &dead_socket);
 }
 
index abc10fe49bd85889fa813aba43c703eeacba4678..8bed1dab903983e4f5d8a11f238b59567931cec0 100644 (file)
@@ -778,7 +778,7 @@ static struct pci_device_id pd6729_pci_ids[] = {
 };
 MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
 
-static struct pci_driver pd6729_pci_drv = {
+static struct pci_driver pd6729_pci_driver = {
        .name           = "pd6729",
        .id_table       = pd6729_pci_ids,
        .probe          = pd6729_pci_probe,
@@ -791,12 +791,12 @@ static struct pci_driver pd6729_pci_drv = {
 
 static int pd6729_module_init(void)
 {
-       return pci_register_driver(&pd6729_pci_drv);
+       return pci_register_driver(&pd6729_pci_driver);
 }
 
 static void pd6729_module_exit(void)
 {
-       pci_unregister_driver(&pd6729_pci_drv);
+       pci_unregister_driver(&pd6729_pci_driver);
 }
 
 module_init(pd6729_module_init);
index 4a05802213c8bdae09138a359bb92ec025d41d2f..881ec8a8e3896bf969213bcc9433d4b9b9a95e3a 100644 (file)
@@ -87,7 +87,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
                default:
                        printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                              __FUNCTION__, state->Vcc);
+                              __func__, state->Vcc);
                        ret = -1;
                }
 
@@ -104,7 +104,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                                pa_dwr_set |= GPIO_A0;
                        else {
                                printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
-                                      __FUNCTION__, state->Vpp);
+                                      __func__, state->Vpp);
                                ret = -1;
                                break;
                        }
@@ -128,14 +128,14 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
                default:
                        printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                              __FUNCTION__, state->Vcc);
+                              __func__, state->Vcc);
                        ret = -1;
                        break;
                }
 
                if (state->Vpp != state->Vcc && state->Vpp != 0) {
                        printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
-                              __FUNCTION__, state->Vpp);
+                              __func__, state->Vpp);
                        ret = -1;
                        break;
                }
index 6fa5eaaab8afcf4188fd27f04bb95aa9c5746d16..145b85e0f02c10a84690d6aa0ccf8dd64bc39304 100644 (file)
@@ -99,7 +99,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
        default:
                 printk(KERN_ERR "%s(): bad Vcc %u\n",
-                                __FUNCTION__, state->Vcc);
+                                __func__, state->Vcc);
                 ret = -1;
        }
 
@@ -111,7 +111,7 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                          power |= MST_PCMCIA_PWR_VPP_VCC;
                  } else {
                          printk(KERN_ERR "%s(): bad Vpp %u\n",
-                                         __FUNCTION__, state->Vpp);
+                                         __func__, state->Vpp);
                          ret = -1;
                  }
        }
index a8d1007077213c96cdc6fe02b7c75d7b198fcde3..0fcf763b9175a077768d6e85b9a933e24ef52967 100644 (file)
@@ -1045,7 +1045,7 @@ static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
                device_remove_file(dev, *attr);
 }
 
-static struct class_interface pccard_rsrc_interface = {
+static struct class_interface pccard_rsrc_interface __refdata = {
        .class = &pcmcia_socket_class,
        .add_dev = &pccard_sysfs_add_rsrc,
        .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
index 7c57fdd3c8d77ae03985175243c72f1f42bf5ba7..ce133ce81c107c30670e5542777a1ec8c44ede87 100644 (file)
@@ -66,14 +66,14 @@ assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_stat
 
        case 50:
                printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
-                       __FUNCTION__);
+                       __func__);
 
        case 33:  /* Can only apply 3.3V to the CF slot. */
                mask = ASSABET_BCR_CF_PWR;
                break;
 
        default:
-               printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+               printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __func__,
                        state->Vcc);
                return -1;
        }
index 62bfc7566ec2a927396bbe48f993b5502fd63d16..607c3f326eca493809022e9c72232cdaddf7a2b8 100644 (file)
@@ -82,14 +82,14 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state
        case 0:
                if ((state->Vcc != 0) &&
                    (state->Vcc != badge4_pcmvcc)) {
-                       complain_about_jumpering(__FUNCTION__, "pcmvcc",
+                       complain_about_jumpering(__func__, "pcmvcc",
                                                 badge4_pcmvcc, state->Vcc);
                        // Apply power regardless of the jumpering.
                        // return -1;
                }
                if ((state->Vpp != 0) &&
                    (state->Vpp != badge4_pcmvpp)) {
-                       complain_about_jumpering(__FUNCTION__, "pcmvpp",
+                       complain_about_jumpering(__func__, "pcmvpp",
                                                 badge4_pcmvpp, state->Vpp);
                        return -1;
                }
@@ -98,7 +98,7 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state
        case 1:
                if ((state->Vcc != 0) &&
                    (state->Vcc != badge4_cfvcc)) {
-                       complain_about_jumpering(__FUNCTION__, "cfvcc",
+                       complain_about_jumpering(__func__, "cfvcc",
                                                 badge4_cfvcc, state->Vcc);
                        return -1;
                }
@@ -143,7 +143,7 @@ int pcmcia_badge4_init(struct device *dev)
        if (machine_is_badge4()) {
                printk(KERN_INFO
                       "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
-                      __FUNCTION__,
+                      __func__,
                       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
 
                ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2);
index 549a1529fe35800e9c6034a6a4940dcf3460caab..7c3951a2675dd2c5ba8ff3b0194a8ac865294a7d 100644 (file)
@@ -63,7 +63,7 @@ cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
        default:
                printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                       __FUNCTION__, state->Vcc);
+                       __func__, state->Vcc);
                return -1;
        }
 
index 6284c35dabc687f6ee1fc5afbf89bda6276ffd46..2167e6714d2dcbee063097e92fbee4411c1fbfe6 100644 (file)
@@ -42,7 +42,7 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
   unsigned int pa_dwr_mask, pa_dwr_set;
   int ret;
 
-printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
+printk("%s(): config socket %d vcc %d vpp %d\n", __func__,
        skt->nr, state->Vcc, state->Vpp);
 
   switch (skt->nr) {
@@ -74,7 +74,7 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
 
   if (state->Vpp != state->Vcc && state->Vpp != 0) {
     printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
-          __FUNCTION__, state->Vpp);
+          __func__, state->Vpp);
     return -1;
   }
 
index 5bc9e9532b9d78f48f00ecd94fdcd5211118bd46..687492fcd5b44254913edd61508c83099e467232 100644 (file)
@@ -59,7 +59,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
                        ncr_set = NCR_A0VPP;
                else {
                        printk(KERN_ERR "%s(): unrecognized VPP %u\n",
-                              __FUNCTION__, state->Vpp);
+                              __func__, state->Vpp);
                        return -1;
                }
                break;
@@ -71,7 +71,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta
 
                if (state->Vpp != state->Vcc && state->Vpp != 0) {
                        printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
-                              __FUNCTION__, state->Vpp);
+                              __func__, state->Vpp);
                        return -1;
                }
                break;
index 9456f5478d09251178534d354a947ffd38032be3..494912fccc0d27dd4cafd93247cc82c4fd3ad52a 100644 (file)
@@ -73,19 +73,19 @@ shannon_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 {
        switch (state->Vcc) {
        case 0: /* power off */
-               printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __FUNCTION__);
+               printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __func__);
                break;
        case 50:
-               printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __FUNCTION__);
+               printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __func__);
        case 33:
                break;
        default:
                printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                      __FUNCTION__, state->Vcc);
+                      __func__, state->Vcc);
                return -1;
        }
 
-       printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __FUNCTION__);
+       printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __func__);
        
        /* Silently ignore Vpp, output enable, speaker enable. */
 
index 04d6f7f75f7806b6ea8fc66f4bc34b4163bbb3c3..42567de894b942916e3dbfeafe1015f4896adb8d 100644 (file)
@@ -90,7 +90,7 @@ simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
        default:
                printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                       __FUNCTION__, state->Vcc);
+                       __func__, state->Vcc);
                clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
                local_irq_restore(flags);
                return -1;
index aa7779d89752681a05e5d10d0aa76c19ff08a648..420a77540f412758979e72b300d7aeac1801b145 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
@@ -353,7 +354,7 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m
                (map->flags&MAP_PREFETCH)?"PREFETCH ":"");
 
        if (map->map >= MAX_IO_WIN) {
-               printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+               printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
                       map->map);
                return -1;
        }
@@ -578,7 +579,7 @@ EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
 
 
 LIST_HEAD(soc_pcmcia_sockets);
-DECLARE_MUTEX(soc_pcmcia_sockets_lock);
+static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
 
 static const char *skt_names[] = {
        "PCMCIA socket 0",
@@ -601,11 +602,11 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
        struct cpufreq_freqs *freqs = data;
        int ret = 0;
 
-       down(&soc_pcmcia_sockets_lock);
+       mutex_lock(&soc_pcmcia_sockets_lock);
        list_for_each_entry(skt, &soc_pcmcia_sockets, node)
                if ( skt->ops->frequency_change )
                        ret += skt->ops->frequency_change(skt, val, freqs);
-       up(&soc_pcmcia_sockets_lock);
+       mutex_unlock(&soc_pcmcia_sockets_lock);
 
        return ret;
 }
@@ -642,7 +643,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
        struct soc_pcmcia_socket *skt;
        int ret, i;
 
-       down(&soc_pcmcia_sockets_lock);
+       mutex_lock(&soc_pcmcia_sockets_lock);
 
        sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
        if (!sinfo) {
@@ -782,7 +783,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
        kfree(sinfo);
 
  out:
-       up(&soc_pcmcia_sockets_lock);
+       mutex_unlock(&soc_pcmcia_sockets_lock);
        return ret;
 }
 
@@ -793,7 +794,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev)
 
        dev_set_drvdata(dev, NULL);
 
-       down(&soc_pcmcia_sockets_lock);
+       mutex_lock(&soc_pcmcia_sockets_lock);
        for (i = 0; i < sinfo->nskt; i++) {
                struct soc_pcmcia_socket *skt = &sinfo->skt[i];
 
@@ -818,7 +819,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev)
        if (list_empty(&soc_pcmcia_sockets))
                soc_pcmcia_cpufreq_unregister();
 
-       up(&soc_pcmcia_sockets_lock);
+       mutex_unlock(&soc_pcmcia_sockets_lock);
 
        kfree(sinfo);
 
index 6f14126889b3457e6c8d7055e9994918e594b793..1edc1da9d3537b208c3af78e8de487e752477f91 100644 (file)
@@ -133,7 +133,6 @@ extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_
 
 
 extern struct list_head soc_pcmcia_sockets;
-extern struct semaphore soc_pcmcia_sockets_lock;
 
 extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr);
 extern int soc_common_drv_pcmcia_remove(struct device *dev);
index b4409002b7f8415a88c4a8a823dbcd0ffa96f530..562384d6f3213b71e0f9f83999b4579b3d3b16e5 100644 (file)
@@ -356,19 +356,23 @@ static ssize_t pccard_store_cis(struct kobject *kobj,
 }
 
 
-static struct device_attribute *pccard_socket_attributes[] = {
-       &dev_attr_card_type,
-       &dev_attr_card_voltage,
-       &dev_attr_card_vpp,
-       &dev_attr_card_vcc,
-       &dev_attr_card_insert,
-       &dev_attr_card_pm_state,
-       &dev_attr_card_eject,
-       &dev_attr_card_irq_mask,
-       &dev_attr_available_resources_setup_done,
+static struct attribute *pccard_socket_attributes[] = {
+       &dev_attr_card_type.attr,
+       &dev_attr_card_voltage.attr,
+       &dev_attr_card_vpp.attr,
+       &dev_attr_card_vcc.attr,
+       &dev_attr_card_insert.attr,
+       &dev_attr_card_pm_state.attr,
+       &dev_attr_card_eject.attr,
+       &dev_attr_card_irq_mask.attr,
+       &dev_attr_available_resources_setup_done.attr,
        NULL,
 };
 
+static const struct attribute_group socket_attrs = {
+       .attrs = pccard_socket_attributes,
+};
+
 static struct bin_attribute pccard_cis_attr = {
        .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
        .size = 0x200,
@@ -376,35 +380,21 @@ static struct bin_attribute pccard_cis_attr = {
        .write = pccard_store_cis,
 };
 
-static int __devinit pccard_sysfs_add_socket(struct device *dev,
-                                            struct class_interface *class_intf)
+int pccard_sysfs_add_socket(struct device *dev)
 {
-       struct device_attribute **attr;
        int ret = 0;
 
-       for (attr = pccard_socket_attributes; *attr; attr++) {
-               ret = device_create_file(dev, *attr);
+       ret = sysfs_create_group(&dev->kobj, &socket_attrs);
+       if (!ret) {
+               ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
                if (ret)
-                       break;
+                       sysfs_remove_group(&dev->kobj, &socket_attrs);
        }
-       if (!ret)
-               ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
-
        return ret;
 }
 
-static void __devexit pccard_sysfs_remove_socket(struct device *dev,
-                                                struct class_interface *class_intf)
+void pccard_sysfs_remove_socket(struct device *dev)
 {
-       struct device_attribute **attr;
-
        sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
-       for (attr = pccard_socket_attributes; *attr; attr++)
-               device_remove_file(dev, *attr);
+       sysfs_remove_group(&dev->kobj, &socket_attrs);
 }
-
-struct class_interface pccard_sysfs_interface = {
-       .class = &pcmcia_socket_class,
-       .add_dev = &pccard_sysfs_add_socket,
-       .remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
-};
index 2e2c457a0fea8e8849f51e4e8d9e4bd36e6be28d..5ff9a4c0447ec8052e0de9a433255051826e1298 100644 (file)
@@ -591,7 +591,8 @@ static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
        p[1] = map & 0xff;
        p[2] = (map >> 8) & 0xff;
 
-       dev_dbg(&dev->dev, "  encode irq %d\n", res->start);
+       dev_dbg(&dev->dev, "  encode irq %llu\n",
+               (unsigned long long)res->start);
 }
 
 static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
@@ -602,7 +603,8 @@ static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
        map = 1 << res->start;
        p[1] = map & 0xff;
 
-       dev_dbg(&dev->dev, "  encode dma %d\n", res->start);
+       dev_dbg(&dev->dev, "  encode dma %llu\n",
+               (unsigned long long)res->start);
 }
 
 static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
index 37b85c67b11dcb2404d0f59eafa021d096f47588..c8bad675dbd1717992c6c1db287415fa4e40b933 100644 (file)
@@ -1055,7 +1055,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level,
                                rec->scsi_result = scsi_cmnd->result;
                                rec->scsi_cmnd = (unsigned long)scsi_cmnd;
                                rec->scsi_serial = scsi_cmnd->serial_number;
-                               memcpy(rec->scsi_opcode, &scsi_cmnd->cmnd,
+                               memcpy(rec->scsi_opcode, scsi_cmnd->cmnd,
                                        min((int)scsi_cmnd->cmd_len,
                                                ZFCP_DBF_SCSI_OPCODE));
                                rec->scsi_retries = scsi_cmnd->retries;
index 9af2330f07a21c0019b0df6d5495427ae4ba38b3..b2ea4ea051f582009a9dace7d8f6a77109271f0c 100644 (file)
@@ -4014,7 +4014,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
                ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n",
                               scpnt->result);
                ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
-                             (void *) &scpnt->cmnd, scpnt->cmd_len);
+                             scpnt->cmnd, scpnt->cmd_len);
 
                ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
                               fcp_rsp_iu->fcp_sns_len);
index f4c4fe90240abdbf995d4c2f8afe0ef9b87374b4..f5a9addb7050d243ea1a5ebd71689b565b2d0214 100644 (file)
@@ -599,7 +599,7 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
                        (struct NCR_700_command_slot *)SCp->host_scribble;
                
                dma_unmap_single(hostdata->dev, slot->pCmd,
-                                sizeof(SCp->cmnd), DMA_TO_DEVICE);
+                                MAX_COMMAND_SIZE, DMA_TO_DEVICE);
                if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
                        char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
 #ifdef NCR_700_DEBUG
@@ -1004,7 +1004,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
                                 * here */
                                NCR_700_unmap(hostdata, SCp, slot);
                                dma_unmap_single(hostdata->dev, slot->pCmd,
-                                                sizeof(SCp->cmnd),
+                                                MAX_COMMAND_SIZE,
                                                 DMA_TO_DEVICE);
 
                                cmnd[0] = REQUEST_SENSE;
@@ -1901,7 +1901,7 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
        }
        slot->resume_offset = 0;
        slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd,
-                                   sizeof(SCp->cmnd), DMA_TO_DEVICE);
+                                   MAX_COMMAND_SIZE, DMA_TO_DEVICE);
        NCR_700_start_command(SCp);
        return 0;
 }
index 99c57b0c1d540c5d8e7d63138ebd76bc7dc4db4f..46d7e400c8be3aed3f5a83fe4f7a214ea0b5d94b 100644 (file)
@@ -504,10 +504,9 @@ config SCSI_AIC7XXX_OLD
 source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
 source "drivers/scsi/aic94xx/Kconfig"
 
-# All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
        tristate "Adaptec I2O RAID support "
-       depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
+       depends on SCSI && PCI && VIRT_TO_BUS
        help
          This driver supports all of Adaptec's I2O based RAID controllers as 
          well as the DPT SmartRaid V cards.  This is an Adaptec maintained
index 792b2e807bf32a6151a38e3c2690e2a33c272f90..ced3eebe252c17164c1b7fe1ab01d82251341f1f 100644 (file)
@@ -895,7 +895,7 @@ static void inia100_build_scb(struct orc_host * host, struct orc_scb * scb, stru
        } else {
                scb->tag_msg = 0;       /* No tag support               */
        }
-       memcpy(&scb->cdb[0], &cmd->cmnd, scb->cdb_len);
+       memcpy(scb->cdb, cmd->cmnd, scb->cdb_len);
 }
 
 /**
index 460d4024c46c4c8118cb841d7c5107f69ed0ef29..aa4e77c252735c593e523ae4a9f516045b674733 100644 (file)
@@ -498,6 +498,11 @@ static void _aac_probe_container2(void * context, struct fib * fibptr)
                    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
                    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
                        fsa_dev_ptr->valid = 1;
+                       /* sense_key holds the current state of the spin-up */
+                       if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
+                               fsa_dev_ptr->sense_data.sense_key = NOT_READY;
+                       else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
+                               fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
                        fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
                        fsa_dev_ptr->size
                          = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
@@ -1509,20 +1514,35 @@ static void io_callback(void *context, struct fib * fibptr)
        scsi_dma_unmap(scsicmd);
 
        readreply = (struct aac_read_reply *)fib_data(fibptr);
-       if (le32_to_cpu(readreply->status) == ST_OK)
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-       else {
+       switch (le32_to_cpu(readreply->status)) {
+       case ST_OK:
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_GOOD;
+               dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
+               break;
+       case ST_NOT_READY:
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_CHECK_CONDITION;
+               set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
+                 SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
+               break;
+       default:
 #ifdef AAC_DETAILED_STATUS_INFO
                printk(KERN_WARNING "io_callback: io failed, status = %d\n",
                  le32_to_cpu(readreply->status));
 #endif
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_CHECK_CONDITION;
                set_sense(&dev->fsa_dev[cid].sense_data,
                  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
                  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
                memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
                       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
                             SCSI_SENSE_BUFFERSIZE));
+               break;
        }
        aac_fib_complete(fibptr);
        aac_fib_free(fibptr);
@@ -1863,6 +1883,84 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
        return SCSI_MLQUEUE_HOST_BUSY;
 }
 
+static void aac_start_stop_callback(void *context, struct fib *fibptr)
+{
+       struct scsi_cmnd *scsicmd = context;
+
+       if (!aac_valid_context(scsicmd, fibptr))
+               return;
+
+       BUG_ON(fibptr == NULL);
+
+       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+       aac_fib_complete(fibptr);
+       aac_fib_free(fibptr);
+       scsicmd->scsi_done(scsicmd);
+}
+
+static int aac_start_stop(struct scsi_cmnd *scsicmd)
+{
+       int status;
+       struct fib *cmd_fibcontext;
+       struct aac_power_management *pmcmd;
+       struct scsi_device *sdev = scsicmd->device;
+       struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+
+       if (!(aac->supplement_adapter_info.SupportedOptions2 &
+             AAC_OPTION_POWER_MANAGEMENT)) {
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                                 SAM_STAT_GOOD;
+               scsicmd->scsi_done(scsicmd);
+               return 0;
+       }
+
+       if (aac->in_reset)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       /*
+        *      Allocate and initialize a Fib
+        */
+       cmd_fibcontext = aac_fib_alloc(aac);
+       if (!cmd_fibcontext)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       aac_fib_init(cmd_fibcontext);
+
+       pmcmd = fib_data(cmd_fibcontext);
+       pmcmd->command = cpu_to_le32(VM_ContainerConfig);
+       pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
+       /* Eject bit ignored, not relevant */
+       pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
+               cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
+       pmcmd->cid = cpu_to_le32(sdev_id(sdev));
+       pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
+               cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
+
+       /*
+        *      Now send the Fib to the adapter
+        */
+       status = aac_fib_send(ContainerCommand,
+                 cmd_fibcontext,
+                 sizeof(struct aac_power_management),
+                 FsaNormal,
+                 0, 1,
+                 (fib_callback)aac_start_stop_callback,
+                 (void *)scsicmd);
+
+       /*
+        *      Check that the command queued to the controller
+        */
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+               return 0;
+       }
+
+       aac_fib_complete(cmd_fibcontext);
+       aac_fib_free(cmd_fibcontext);
+       return SCSI_MLQUEUE_HOST_BUSY;
+}
+
 /**
  *     aac_scsi_cmd()          -       Process SCSI command
  *     @scsicmd:               SCSI command block
@@ -1899,7 +1997,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                         *      If the target container doesn't exist, it may have
                         *      been newly created
                         */
-                       if ((fsa_dev_ptr[cid].valid & 1) == 0) {
+                       if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
+                         (fsa_dev_ptr[cid].sense_data.sense_key ==
+                          NOT_READY)) {
                                switch (scsicmd->cmnd[0]) {
                                case SERVICE_ACTION_IN:
                                        if (!(dev->raw_io_interface) ||
@@ -2091,8 +2191,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
                /* Do not cache partition table for arrays */
                scsicmd->device->removable = 1;
-
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                 SAM_STAT_GOOD;
                scsicmd->scsi_done(scsicmd);
 
                return 0;
@@ -2187,15 +2287,32 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
         *      These commands are all No-Ops
         */
        case TEST_UNIT_READY:
+               if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
+                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                               SAM_STAT_CHECK_CONDITION;
+                       set_sense(&dev->fsa_dev[cid].sense_data,
+                                 NOT_READY, SENCODE_BECOMING_READY,
+                                 ASENCODE_BECOMING_READY, 0, 0);
+                       memcpy(scsicmd->sense_buffer,
+                              &dev->fsa_dev[cid].sense_data,
+                              min_t(size_t,
+                                    sizeof(dev->fsa_dev[cid].sense_data),
+                                    SCSI_SENSE_BUFFERSIZE));
+                       scsicmd->scsi_done(scsicmd);
+                       return 0;
+               }
+               /* FALLTHRU */
        case RESERVE:
        case RELEASE:
        case REZERO_UNIT:
        case REASSIGN_BLOCKS:
        case SEEK_10:
-       case START_STOP:
                scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                scsicmd->scsi_done(scsicmd);
                return 0;
+
+       case START_STOP:
+               return aac_start_stop(scsicmd);
        }
 
        switch (scsicmd->cmnd[0])
index 113ca9c8934c775e05164f9ab302645bd9c15d53..73916adb8f80f21d587cf1fbe499a14252c042fb 100644 (file)
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2455
+# define AAC_DRIVER_BUILD 2456
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
@@ -34,8 +34,8 @@
 #define CONTAINER_TO_ID(cont)          (cont)
 #define CONTAINER_TO_LUN(cont)         (0)
 
-#define aac_phys_to_logical(x)  (x+1)
-#define aac_logical_to_phys(x)  (x?x-1:0)
+#define aac_phys_to_logical(x)  ((x)+1)
+#define aac_logical_to_phys(x)  ((x)?(x)-1:0)
 
 /* #define AAC_DETAILED_STATUS_INFO */
 
@@ -424,6 +424,8 @@ struct aac_init
         */
        __le32  InitFlags;      /* flags for supported features */
 #define INITFLAGS_NEW_COMM_SUPPORTED   0x00000001
+#define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010
+#define INITFLAGS_DRIVER_SUPPORTS_PM   0x00000020
        __le32  MaxIoCommands;  /* max outstanding commands */
        __le32  MaxIoSize;      /* largest I/O command */
        __le32  MaxFibSize;     /* largest FIB to adapter */
@@ -867,8 +869,10 @@ struct aac_supplement_adapter_info
 };
 #define AAC_FEATURE_FALCON     cpu_to_le32(0x00000010)
 #define AAC_FEATURE_JBOD       cpu_to_le32(0x08000000)
-#define AAC_OPTION_MU_RESET    cpu_to_le32(0x00000001)
-#define AAC_OPTION_IGNORE_RESET        cpu_to_le32(0x00000002)
+/* SupportedOptions2 */
+#define AAC_OPTION_MU_RESET            cpu_to_le32(0x00000001)
+#define AAC_OPTION_IGNORE_RESET                cpu_to_le32(0x00000002)
+#define AAC_OPTION_POWER_MANAGEMENT    cpu_to_le32(0x00000004)
 #define AAC_SIS_VERSION_V3     3
 #define AAC_SIS_SLOT_UNKNOWN   0xFF
 
@@ -1148,6 +1152,7 @@ struct aac_dev
 #define                ST_DQUOT        69
 #define                ST_STALE        70
 #define                ST_REMOTE       71
+#define                ST_NOT_READY    72
 #define                ST_BADHANDLE    10001
 #define                ST_NOT_SYNC     10002
 #define                ST_BAD_COOKIE   10003
@@ -1269,6 +1274,18 @@ struct aac_synchronize_reply {
        u8              data[16];
 };
 
+#define CT_POWER_MANAGEMENT    245
+#define CT_PM_START_UNIT       2
+#define CT_PM_STOP_UNIT                3
+#define CT_PM_UNIT_IMMEDIATE   1
+struct aac_power_management {
+       __le32          command;        /* VM_ContainerConfig */
+       __le32          type;           /* CT_POWER_MANAGEMENT */
+       __le32          sub;            /* CT_PM_* */
+       __le32          cid;
+       __le32          parm;           /* CT_PM_sub_* */
+};
+
 #define CT_PAUSE_IO    65
 #define CT_RELEASE_IO  66
 struct aac_pause {
@@ -1536,6 +1553,7 @@ struct aac_mntent {
 #define FSCS_NOTCLEAN  0x0001  /* fsck is necessary before mounting */
 #define FSCS_READONLY  0x0002  /* possible result of broken mirror */
 #define FSCS_HIDDEN    0x0004  /* should be ignored - set during a clear */
+#define FSCS_NOT_READY 0x0008  /* Array spinning up to fulfil request */
 
 struct aac_query_mount {
        __le32          command;
index 294a802450be2efafe4cb0381b9c01c88920aa79..cbac063551073c4db0a0401d05281e7844b72320 100644 (file)
@@ -97,6 +97,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
                init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
                dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
        }
+       init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
+                                      INITFLAGS_DRIVER_SUPPORTS_PM);
        init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
        init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
        init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
index ef67816a6fe5940211247e96e1299343e3f4a298..289304aab690d065e0e65dbb11ede16b87f7f808 100644 (file)
@@ -515,7 +515,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                                }
                                udelay(5);
                        }
-               } else if (down_interruptible(&fibptr->event_wait) == 0) {
+               } else if (down_interruptible(&fibptr->event_wait)) {
                        fibptr->done = 2;
                        up(&fibptr->event_wait);
                }
@@ -906,15 +906,22 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                case AifEnAddJBOD:
                case AifEnDeleteJBOD:
                        container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
-                       if ((container >> 28))
+                       if ((container >> 28)) {
+                               container = (u32)-1;
                                break;
+                       }
                        channel = (container >> 24) & 0xF;
-                       if (channel >= dev->maximum_num_channels)
+                       if (channel >= dev->maximum_num_channels) {
+                               container = (u32)-1;
                                break;
+                       }
                        id = container & 0xFFFF;
-                       if (id >= dev->maximum_num_physicals)
+                       if (id >= dev->maximum_num_physicals) {
+                               container = (u32)-1;
                                break;
+                       }
                        lun = (container >> 16) & 0xFF;
+                       container = (u32)-1;
                        channel = aac_phys_to_logical(channel);
                        device_config_needed =
                          (((__le32 *)aifcmd->data)[0] ==
@@ -933,13 +940,18 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                        case EM_DRIVE_REMOVAL:
                                container = le32_to_cpu(
                                        ((__le32 *)aifcmd->data)[2]);
-                               if ((container >> 28))
+                               if ((container >> 28)) {
+                                       container = (u32)-1;
                                        break;
+                               }
                                channel = (container >> 24) & 0xF;
-                               if (channel >= dev->maximum_num_channels)
+                               if (channel >= dev->maximum_num_channels) {
+                                       container = (u32)-1;
                                        break;
+                               }
                                id = container & 0xFFFF;
                                lun = (container >> 16) & 0xFF;
+                               container = (u32)-1;
                                if (id >= dev->maximum_num_physicals) {
                                        /* legacy dev_t ? */
                                        if ((0x2000 <= id) || lun || channel ||
@@ -1025,9 +1037,10 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                break;
        }
 
+       container = 0;
+retry_next:
        if (device_config_needed == NOTHING)
-       for (container = 0; container < dev->maximum_num_containers;
-           ++container) {
+       for (; container < dev->maximum_num_containers; ++container) {
                if ((dev->fsa_dev[container].config_waiting_on == 0) &&
                        (dev->fsa_dev[container].config_needed != NOTHING) &&
                        time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) {
@@ -1110,6 +1123,11 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
        }
        if (device_config_needed == ADD)
                scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
+       if (channel == CONTAINER_CHANNEL) {
+               container++;
+               device_config_needed = NOTHING;
+               goto retry_next;
+       }
 }
 
 static int _aac_reset_adapter(struct aac_dev *aac, int forced)
index c109f63f827940e275c886e462280bca459c0997..1f7c83607f84729a918c640e83a67daf9e45643e 100644 (file)
@@ -401,6 +401,8 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
 static int aac_slave_configure(struct scsi_device *sdev)
 {
        struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+       if (aac->jbod && (sdev->type == TYPE_DISK))
+               sdev->removable = 1;
        if ((sdev->type == TYPE_DISK) &&
                        (sdev_channel(sdev) != CONTAINER_CHANNEL) &&
                        (!aac->jbod || sdev->inq_periph_qual) &&
@@ -809,6 +811,12 @@ static ssize_t aac_show_flags(struct device *cdev,
                                "SAI_READ_CAPACITY_16\n");
        if (dev->jbod)
                len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
+       if (dev->supplement_adapter_info.SupportedOptions2 &
+               AAC_OPTION_POWER_MANAGEMENT)
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                               "SUPPORTED_POWER_MANAGEMENT\n");
+       if (dev->msi)
+               len += snprintf(buf + len, PAGE_SIZE - len, "PCI_HAS_MSI\n");
        return len;
 }
 
@@ -1106,7 +1114,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        aac->pdev = pdev;
        aac->name = aac_driver_template.name;
        aac->id = shost->unique_id;
-       aac->cardtype =  index;
+       aac->cardtype = index;
        INIT_LIST_HEAD(&aac->entry);
 
        aac->fibs = kmalloc(sizeof(struct fib) * (shost->can_queue + AAC_NUM_MGT_FIB), GFP_KERNEL);
@@ -1146,19 +1154,19 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
                goto out_deinit;
 
        /*
-        * Lets override negotiations and drop the maximum SG limit to 34
-        */
+        * Lets override negotiations and drop the maximum SG limit to 34
+        */
        if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
                        (shost->sg_tablesize > 34)) {
                shost->sg_tablesize = 34;
                shost->max_sectors = (shost->sg_tablesize * 8) + 112;
-       }
+       }
 
-       if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
+       if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
                        (shost->sg_tablesize > 17)) {
                shost->sg_tablesize = 17;
                shost->max_sectors = (shost->sg_tablesize * 8) + 112;
-       }
+       }
 
        error = pci_set_dma_max_seg_size(pdev,
                (aac->adapter_info.options & AAC_OPT_NEW_COMM) ?
@@ -1174,7 +1182,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        else
                aac->printf_enabled = 0;
 
-       /*
+       /*
         * max channel will be the physical channels plus 1 virtual channel
         * all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
         * physical channels are address by their actual physical number+1
index 90f5e0a6f2e3f77fbe024850a3de235589bb1ccb..2a730c470f6265abf3d1add4bf77bb8eb4280b96 100644 (file)
@@ -529,10 +529,10 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
 /* The first entry, 0, is used for dynamic ids, the rest for devices
  * we know about.
  */
-static struct asd_pcidev_struct {
+static const struct asd_pcidev_struct {
        const char * name;
        int (*setup)(struct asd_ha_struct *asd_ha);
-} asd_pcidev_data[] = {
+} asd_pcidev_data[] __devinitconst = {
        /* Id 0 is used for dynamic ids. */
        { .name  = "Adaptec AIC-94xx SAS/SATA Host Adapter",
          .setup = asd_aic9410_setup
@@ -735,7 +735,7 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
 static int __devinit asd_pci_probe(struct pci_dev *dev,
                                   const struct pci_device_id *id)
 {
-       struct asd_pcidev_struct *asd_dev;
+       const struct asd_pcidev_struct *asd_dev;
        unsigned asd_id = (unsigned) id->driver_data;
        struct asd_ha_struct *asd_ha;
        struct Scsi_Host *shost;
index 403a7f2d8f9b21a92fbd2b687560b06e71e5db99..9785d7384199f8c457b346354b73455b8b509151 100644 (file)
@@ -28,7 +28,6 @@
 #define SERVICE_ACTION_OUT_12 0xa9
 #define SERVICE_ACTION_IN_16 0x9e
 #define SERVICE_ACTION_OUT_16 0x9f
-#define VARIABLE_LENGTH_CMD 0x7f
 
 
 
@@ -210,7 +209,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
        cdb0 = cdbp[0];
        switch(cdb0) {
        case VARIABLE_LENGTH_CMD:
-               len = cdbp[7] + 8;
+               len = scsi_varlen_cdb_length(cdbp);
                if (len < 10) {
                        printk("short variable length command, "
                               "len=%d ext_len=%d", len, cdb_len);
@@ -300,7 +299,7 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len)
        cdb0 = cdbp[0];
        switch(cdb0) {
        case VARIABLE_LENGTH_CMD:
-               len = cdbp[7] + 8;
+               len = scsi_varlen_cdb_length(cdbp);
                if (len < 10) {
                        printk("short opcode=0x%x command, len=%d "
                               "ext_len=%d", cdb0, len, cdb_len);
@@ -335,10 +334,7 @@ void __scsi_print_command(unsigned char *cdb)
        int k, len;
 
        print_opcode_name(cdb, 0);
-       if (VARIABLE_LENGTH_CMD == cdb[0])
-               len = cdb[7] + 8;
-       else
-               len = COMMAND_SIZE(cdb[0]);
+       len = scsi_command_size(cdb);
        /* print out all bytes in cdb */
        for (k = 0; k < len; ++k) 
                printk(" %02x", cdb[k]);
index cc784e8f6e9d04fef20a29b83bb1cfdec02b3ad2..f60236721e0ddef2074fdd3b08538a3ba1acc67f 100644 (file)
@@ -89,7 +89,7 @@ typedef struct {
        int      njobs;            /* # of jobs sent to HA            */
        int      qdepth;           /* Controller queue depth.         */
        int      wakebase;         /* mpx wakeup base index.          */
-       uLONG    SGsize;           /* Scatter/Gather list size.       */
+       uINT     SGsize;           /* Scatter/Gather list size.       */
        unsigned heads;            /* heads for drives on cntlr.      */
        unsigned sectors;          /* sectors for drives on cntlr.    */
        uCHAR    do_drive32;       /* Flag for Above 16 MB Ability    */
@@ -97,8 +97,8 @@ typedef struct {
        char     idPAL[4];         /* 4 Bytes Of The ID Pal           */
        uCHAR    primary;          /* 1 For Primary, 0 For Secondary  */
        uCHAR    eataVersion;      /* EATA Version                    */
-       uLONG    cpLength;         /* EATA Command Packet Length      */
-       uLONG    spLength;         /* EATA Status Packet Length       */
+       uINT     cpLength;         /* EATA Command Packet Length      */
+       uINT     spLength;         /* EATA Status Packet Length       */
        uCHAR    drqNum;           /* DRQ Index (0,5,6,7)             */
        uCHAR    flag1;            /* EATA Flags 1 (Byte 9)           */
        uCHAR    flag2;            /* EATA Flags 2 (Byte 30)          */
@@ -107,23 +107,23 @@ typedef struct {
 typedef struct {
        uSHORT length;          // Remaining length of this
        uSHORT drvrHBAnum;      // Relative HBA # used by the driver
-       uLONG baseAddr;         // Base I/O address
+       uINT baseAddr;          // Base I/O address
        uSHORT blinkState;      // Blink LED state (0=Not in blink LED)
        uCHAR pciBusNum;        // PCI Bus # (Optional)
        uCHAR pciDeviceNum;     // PCI Device # (Optional)
        uSHORT hbaFlags;        // Miscellaneous HBA flags
        uSHORT Interrupt;       // Interrupt set for this device.
 #   if (defined(_DPT_ARC))
-       uLONG baseLength;
+       uINT baseLength;
        ADAPTER_OBJECT *AdapterObject;
        LARGE_INTEGER DmaLogicalAddress;
        PVOID DmaVirtualAddress;
        LARGE_INTEGER ReplyLogicalAddress;
        PVOID ReplyVirtualAddress;
 #   else
-       uLONG reserved1;        // Reserved for future expansion
-       uLONG reserved2;        // Reserved for future expansion
-       uLONG reserved3;        // Reserved for future expansion
+       uINT reserved1;         // Reserved for future expansion
+       uINT reserved2;         // Reserved for future expansion
+       uINT reserved3;         // Reserved for future expansion
 #   endif
 } drvrHBAinfo_S;
 
index 94bc894d1200f255d6ef98a3ec74f4c27a8b1a0a..72c8992fdf21e089f5c25b6dfd2c42d507c0eb3c 100644 (file)
 /* to make sure we are talking the same size under all OS's     */
 typedef unsigned char sigBYTE;
 typedef unsigned short sigWORD;
-#if (defined(_MULTI_DATAMODEL) && defined(sun) && !defined(_ILP32))
-typedef uint32_t sigLONG;
-#else
-typedef unsigned long sigLONG;
-#endif
+typedef unsigned int sigINT;
 
 /*
  * use sigWORDLittleEndian for:
@@ -300,7 +296,7 @@ typedef struct dpt_sig {
     sigBYTE dsFiletype;          /* type of file */
     sigBYTE dsFiletypeFlags;     /* flags to specify load type, etc. */
     sigBYTE dsOEM;               /* OEM file was created for */
-    sigLONG dsOS;                /* which Operating systems */
+    sigINT  dsOS;                /* which Operating systems */
     sigWORD dsCapabilities;      /* RAID levels, etc. */
     sigWORD dsDeviceSupp;        /* Types of SCSI devices supported */
     sigWORD dsAdapterSupp;       /* DPT adapter families supported */
index d23b70c8c768c3cc9ad782175496cbebc1c7436c..a90c4cb8ea8b29cb29abf267a1b74d5baf64ca35 100644 (file)
    uCHAR        smartROMRevision;
    uSHORT       flags;                  /* See bit definitions above */
    uSHORT       conventionalMemSize;    /* in KB */
-   uLONG        extendedMemSize;        /* in KB */
-   uLONG        osType;                 /* Same as DPTSIG's definition */
+   uINT         extendedMemSize;        /* in KB */
+   uINT         osType;                 /* Same as DPTSIG's definition */
    uCHAR        osMajorVersion;
    uCHAR        osMinorVersion;         /* The OS version */
    uCHAR        osRevision;
index ac92ac143b46783bc9df6323bcfee84680189e8f..0fb5bf4c43acd4500b93bc51b1e010c17e3a70d7 100644 (file)
 /*#define DEBUG 1 */
 /*#define UARTDELAY 1 */
 
-/* On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates
-   high pages. Keep the macro around because of the broken unmerged ia64 tree */
-
-#define ADDR32 (0)
-
 #include <linux/module.h>
 
 MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
@@ -108,27 +103,28 @@ static dpt_sig_S DPTI_sig = {
 
 static DEFINE_MUTEX(adpt_configuration_lock);
 
-static struct i2o_sys_tbl *sys_tbl = NULL;
-static int sys_tbl_ind = 0;
-static int sys_tbl_len = 0;
+static struct i2o_sys_tbl *sys_tbl;
+static dma_addr_t sys_tbl_pa;
+static int sys_tbl_ind;
+static int sys_tbl_len;
 
 static adpt_hba* hba_chain = NULL;
 static int hba_count = 0;
 
+static struct class *adpt_sysfs_class;
+
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *, unsigned int, unsigned long);
+#endif
+
 static const struct file_operations adpt_fops = {
        .ioctl          = adpt_ioctl,
        .open           = adpt_open,
-       .release        = adpt_close
-};
-
-#ifdef REBOOT_NOTIFIER
-static struct notifier_block adpt_reboot_notifier =
-{
-        adpt_reboot_event,
-        NULL,
-        0
-};
+       .release        = adpt_close,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = compat_adpt_ioctl,
 #endif
+};
 
 /* Structures and definitions for synchronous message posting.
  * See adpt_i2o_post_wait() for description
@@ -151,6 +147,21 @@ static DEFINE_SPINLOCK(adpt_post_wait_lock);
  *============================================================================
  */
 
+static inline int dpt_dma64(adpt_hba *pHba)
+{
+       return (sizeof(dma_addr_t) > 4 && (pHba)->dma64);
+}
+
+static inline u32 dma_high(dma_addr_t addr)
+{
+       return upper_32_bits(addr);
+}
+
+static inline u32 dma_low(dma_addr_t addr)
+{
+       return (u32)addr;
+}
+
 static u8 adpt_read_blink_led(adpt_hba* host)
 {
        if (host->FwDebugBLEDflag_P) {
@@ -178,8 +189,6 @@ static int adpt_detect(struct scsi_host_template* sht)
        struct pci_dev *pDev = NULL;
        adpt_hba* pHba;
 
-       adpt_init();
-
        PINFO("Detecting Adaptec I2O RAID controllers...\n");
 
         /* search for all Adatpec I2O RAID cards */
@@ -247,13 +256,29 @@ rebuild_sys_tab:
                adpt_inquiry(pHba);
        }
 
+       adpt_sysfs_class = class_create(THIS_MODULE, "dpt_i2o");
+       if (IS_ERR(adpt_sysfs_class)) {
+               printk(KERN_WARNING"dpti: unable to create dpt_i2o class\n");
+               adpt_sysfs_class = NULL;
+       }
+
        for (pHba = hba_chain; pHba; pHba = pHba->next) {
-               if( adpt_scsi_register(pHba,sht) < 0){
+               if (adpt_scsi_host_alloc(pHba, sht) < 0){
                        adpt_i2o_delete_hba(pHba);
                        continue;
                }
                pHba->initialized = TRUE;
                pHba->state &= ~DPTI_STATE_RESET;
+               if (adpt_sysfs_class) {
+                       struct device *dev = device_create(adpt_sysfs_class,
+                               NULL, MKDEV(DPTI_I2O_MAJOR, pHba->unit),
+                               "dpti%d", pHba->unit);
+                       if (IS_ERR(dev)) {
+                               printk(KERN_WARNING"dpti%d: unable to "
+                                       "create device in dpt_i2o class\n",
+                                       pHba->unit);
+                       }
+               }
        }
 
        // Register our control device node
@@ -282,7 +307,7 @@ static int adpt_release(struct Scsi_Host *host)
 
 static void adpt_inquiry(adpt_hba* pHba)
 {
-       u32 msg[14]; 
+       u32 msg[17]; 
        u32 *mptr;
        u32 *lenptr;
        int direction;
@@ -290,11 +315,12 @@ static void adpt_inquiry(adpt_hba* pHba)
        u32 len;
        u32 reqlen;
        u8* buf;
+       dma_addr_t addr;
        u8  scb[16];
        s32 rcode;
 
        memset(msg, 0, sizeof(msg));
-       buf = kmalloc(80,GFP_KERNEL|ADDR32);
+       buf = dma_alloc_coherent(&pHba->pDev->dev, 80, &addr, GFP_KERNEL);
        if(!buf){
                printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name);
                return;
@@ -305,7 +331,10 @@ static void adpt_inquiry(adpt_hba* pHba)
        direction = 0x00000000; 
        scsidir  =0x40000000;   // DATA IN  (iop<--dev)
 
-       reqlen = 14;            // SINGLE SGE
+       if (dpt_dma64(pHba))
+               reqlen = 17;            // SINGLE SGE, 64 bit
+       else
+               reqlen = 14;            // SINGLE SGE, 32 bit
        /* Stick the headers on */
        msg[0] = reqlen<<16 | SGL_OFFSET_12;
        msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID);
@@ -338,8 +367,16 @@ static void adpt_inquiry(adpt_hba* pHba)
 
        /* Now fill in the SGList and command */
        *lenptr = len;
-       *mptr++ = 0xD0000000|direction|len;
-       *mptr++ = virt_to_bus(buf);
+       if (dpt_dma64(pHba)) {
+               *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+               *mptr++ = 1 << PAGE_SHIFT;
+               *mptr++ = 0xD0000000|direction|len;
+               *mptr++ = dma_low(addr);
+               *mptr++ = dma_high(addr);
+       } else {
+               *mptr++ = 0xD0000000|direction|len;
+               *mptr++ = addr;
+       }
 
        // Send it on it's way
        rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120);
@@ -347,7 +384,7 @@ static void adpt_inquiry(adpt_hba* pHba)
                sprintf(pHba->detail, "Adaptec I2O RAID");
                printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode);
                if (rcode != -ETIME && rcode != -EINTR)
-                       kfree(buf);
+                       dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
        } else {
                memset(pHba->detail, 0, sizeof(pHba->detail));
                memcpy(&(pHba->detail), "Vendor: Adaptec ", 16);
@@ -356,7 +393,7 @@ static void adpt_inquiry(adpt_hba* pHba)
                memcpy(&(pHba->detail[40]), " FW: ", 4);
                memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4);
                pHba->detail[48] = '\0';        /* precautionary */
-               kfree(buf);
+               dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
        }
        adpt_i2o_status_get(pHba);
        return ;
@@ -632,6 +669,91 @@ stop_output:
        return len;
 }
 
+/*
+ *     Turn a struct scsi_cmnd * into a unique 32 bit 'context'.
+ */
+static u32 adpt_cmd_to_context(struct scsi_cmnd *cmd)
+{
+       return (u32)cmd->serial_number;
+}
+
+/*
+ *     Go from a u32 'context' to a struct scsi_cmnd * .
+ *     This could probably be made more efficient.
+ */
+static struct scsi_cmnd *
+       adpt_cmd_from_context(adpt_hba * pHba, u32 context)
+{
+       struct scsi_cmnd * cmd;
+       struct scsi_device * d;
+
+       if (context == 0)
+               return NULL;
+
+       spin_unlock(pHba->host->host_lock);
+       shost_for_each_device(d, pHba->host) {
+               unsigned long flags;
+               spin_lock_irqsave(&d->list_lock, flags);
+               list_for_each_entry(cmd, &d->cmd_list, list) {
+                       if (((u32)cmd->serial_number == context)) {
+                               spin_unlock_irqrestore(&d->list_lock, flags);
+                               scsi_device_put(d);
+                               spin_lock(pHba->host->host_lock);
+                               return cmd;
+                       }
+               }
+               spin_unlock_irqrestore(&d->list_lock, flags);
+       }
+       spin_lock(pHba->host->host_lock);
+
+       return NULL;
+}
+
+/*
+ *     Turn a pointer to ioctl reply data into an u32 'context'
+ */
+static u32 adpt_ioctl_to_context(adpt_hba * pHba, void *reply)
+{
+#if BITS_PER_LONG == 32
+       return (u32)(unsigned long)reply;
+#else
+       ulong flags = 0;
+       u32 nr, i;
+
+       spin_lock_irqsave(pHba->host->host_lock, flags);
+       nr = ARRAY_SIZE(pHba->ioctl_reply_context);
+       for (i = 0; i < nr; i++) {
+               if (pHba->ioctl_reply_context[i] == NULL) {
+                       pHba->ioctl_reply_context[i] = reply;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(pHba->host->host_lock, flags);
+       if (i >= nr) {
+               kfree (reply);
+               printk(KERN_WARNING"%s: Too many outstanding "
+                               "ioctl commands\n", pHba->name);
+               return (u32)-1;
+       }
+
+       return i;
+#endif
+}
+
+/*
+ *     Go from an u32 'context' to a pointer to ioctl reply data.
+ */
+static void *adpt_ioctl_from_context(adpt_hba *pHba, u32 context)
+{
+#if BITS_PER_LONG == 32
+       return (void *)(unsigned long)context;
+#else
+       void *p = pHba->ioctl_reply_context[context];
+       pHba->ioctl_reply_context[context] = NULL;
+
+       return p;
+#endif
+}
 
 /*===========================================================================
  * Error Handling routines
@@ -660,7 +782,7 @@ static int adpt_abort(struct scsi_cmnd * cmd)
        msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid;
        msg[2] = 0;
        msg[3]= 0; 
-       msg[4] = (u32)cmd;
+       msg[4] = adpt_cmd_to_context(cmd);
        if (pHba->host)
                spin_lock_irq(pHba->host->host_lock);
        rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER);
@@ -861,27 +983,6 @@ static void adpt_i2o_sys_shutdown(void)
         printk(KERN_INFO "Adaptec I2O controllers down.\n");
 }
 
-/*
- * reboot/shutdown notification.
- *
- * - Quiesce each IOP in the system
- *
- */
-
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p)
-{
-
-        if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
-                 return NOTIFY_DONE;
-
-        adpt_i2o_sys_shutdown();
-
-        return NOTIFY_DONE;
-}
-#endif
-
-
 static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev)
 {
 
@@ -893,6 +994,7 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
        u32 hba_map1_area_size = 0;
        void __iomem *base_addr_virt = NULL;
        void __iomem *msg_addr_virt = NULL;
+       int dma64 = 0;
 
        int raptorFlag = FALSE;
 
@@ -906,9 +1008,21 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
        }
 
        pci_set_master(pDev);
-       if (pci_set_dma_mask(pDev, DMA_32BIT_MASK))
+
+       /*
+        *      See if we should enable dma64 mode.
+        */
+       if (sizeof(dma_addr_t) > 4 &&
+           pci_set_dma_mask(pDev, DMA_64BIT_MASK) == 0) {
+               if (dma_get_required_mask(&pDev->dev) > DMA_32BIT_MASK)
+                       dma64 = 1;
+       }
+       if (!dma64 && pci_set_dma_mask(pDev, DMA_32BIT_MASK) != 0)
                return -EINVAL;
 
+       /* adapter only supports message blocks below 4GB */
+       pci_set_consistent_dma_mask(pDev, DMA_32BIT_MASK);
+
        base_addr0_phys = pci_resource_start(pDev,0);
        hba_map0_area_size = pci_resource_len(pDev,0);
 
@@ -929,6 +1043,25 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
                raptorFlag = TRUE;
        }
 
+#if BITS_PER_LONG == 64
+       /*
+        *      The original Adaptec 64 bit driver has this comment here:
+        *      "x86_64 machines need more optimal mappings"
+        *
+        *      I assume some HBAs report ridiculously large mappings
+        *      and we need to limit them on platforms with IOMMUs.
+        */
+       if (raptorFlag == TRUE) {
+               if (hba_map0_area_size > 128)
+                       hba_map0_area_size = 128;
+               if (hba_map1_area_size > 524288)
+                       hba_map1_area_size = 524288;
+       } else {
+               if (hba_map0_area_size > 524288)
+                       hba_map0_area_size = 524288;
+       }
+#endif
+
        base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
        if (!base_addr_virt) {
                pci_release_regions(pDev);
@@ -991,16 +1124,22 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
        pHba->state = DPTI_STATE_RESET;
        pHba->pDev = pDev;
        pHba->devices = NULL;
+       pHba->dma64 = dma64;
 
        // Initializing the spinlocks
        spin_lock_init(&pHba->state_lock);
        spin_lock_init(&adpt_post_wait_lock);
 
        if(raptorFlag == 0){
-               printk(KERN_INFO"Adaptec I2O RAID controller %d at %p size=%x irq=%d\n", 
-                       hba_count-1, base_addr_virt, hba_map0_area_size, pDev->irq);
+               printk(KERN_INFO "Adaptec I2O RAID controller"
+                                " %d at %p size=%x irq=%d%s\n", 
+                       hba_count-1, base_addr_virt,
+                       hba_map0_area_size, pDev->irq,
+                       dma64 ? " (64-bit DMA)" : "");
        } else {
-               printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d\n",hba_count-1, pDev->irq);
+               printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d%s\n",
+                       hba_count-1, pDev->irq,
+                       dma64 ? " (64-bit DMA)" : "");
                printk(KERN_INFO"     BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size);
                printk(KERN_INFO"     BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
        }
@@ -1053,10 +1192,26 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
        if(pHba->msg_addr_virt != pHba->base_addr_virt){
                iounmap(pHba->msg_addr_virt);
        }
-       kfree(pHba->hrt);
-       kfree(pHba->lct);
-       kfree(pHba->status_block);
-       kfree(pHba->reply_pool);
+       if(pHba->FwDebugBuffer_P)
+               iounmap(pHba->FwDebugBuffer_P);
+       if(pHba->hrt) {
+               dma_free_coherent(&pHba->pDev->dev,
+                       pHba->hrt->num_entries * pHba->hrt->entry_len << 2,
+                       pHba->hrt, pHba->hrt_pa);
+       }
+       if(pHba->lct) {
+               dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+                       pHba->lct, pHba->lct_pa);
+       }
+       if(pHba->status_block) {
+               dma_free_coherent(&pHba->pDev->dev, sizeof(i2o_status_block),
+                       pHba->status_block, pHba->status_block_pa);
+       }
+       if(pHba->reply_pool) {
+               dma_free_coherent(&pHba->pDev->dev,
+                       pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+                       pHba->reply_pool, pHba->reply_pool_pa);
+       }
 
        for(d = pHba->devices; d ; d = next){
                next = d->next;
@@ -1075,23 +1230,19 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
        pci_dev_put(pHba->pDev);
        kfree(pHba);
 
+       if (adpt_sysfs_class)
+               device_destroy(adpt_sysfs_class,
+                               MKDEV(DPTI_I2O_MAJOR, pHba->unit));
+
        if(hba_count <= 0){
                unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);   
+               if (adpt_sysfs_class) {
+                       class_destroy(adpt_sysfs_class);
+                       adpt_sysfs_class = NULL;
+               }
        }
 }
 
-
-static int adpt_init(void)
-{
-       printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
-#ifdef REBOOT_NOTIFIER
-       register_reboot_notifier(&adpt_reboot_notifier);
-#endif
-
-       return 0;
-}
-
-
 static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun)
 {
        struct adpt_device* d;
@@ -1283,6 +1434,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
 {
        u32 msg[8];
        u8* status;
+       dma_addr_t addr;
        u32 m = EMPTY_QUEUE ;
        ulong timeout = jiffies + (TMOUT_IOPRESET*HZ);
 
@@ -1305,12 +1457,13 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
                schedule_timeout_uninterruptible(1);
        } while (m == EMPTY_QUEUE);
 
-       status = kzalloc(4, GFP_KERNEL|ADDR32);
+       status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
        if(status == NULL) {
                adpt_send_nop(pHba, m);
                printk(KERN_ERR"IOP reset failed - no free memory.\n");
                return -ENOMEM;
        }
+       memset(status,0,4);
 
        msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1318,8 +1471,8 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
        msg[3]=0;
        msg[4]=0;
        msg[5]=0;
-       msg[6]=virt_to_bus(status);
-       msg[7]=0;     
+       msg[6]=dma_low(addr);
+       msg[7]=dma_high(addr);
 
        memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg));
        wmb();
@@ -1329,7 +1482,10 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
        while(*status == 0){
                if(time_after(jiffies,timeout)){
                        printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name);
-                       kfree(status);
+                       /* We lose 4 bytes of "status" here, but we cannot
+                          free these because controller may awake and corrupt
+                          those bytes at any time */
+                       /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
                        return -ETIMEDOUT;
                }
                rmb();
@@ -1348,6 +1504,10 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
                        }
                        if(time_after(jiffies,timeout)){
                                printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);
+                               /* We lose 4 bytes of "status" here, but we
+                                  cannot free these because controller may
+                                  awake and corrupt those bytes at any time */
+                               /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
                                return -ETIMEDOUT;
                        }
                        schedule_timeout_uninterruptible(1);
@@ -1364,7 +1524,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
                PDEBUG("%s: Reset completed.\n", pHba->name);
        }
 
-       kfree(status);
+       dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
 #ifdef UARTDELAY
        // This delay is to allow someone attached to the card through the debug UART to 
        // set up the dump levels that they want before the rest of the initialization sequence
@@ -1636,6 +1796,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
        u32 i = 0;
        u32 rcode = 0;
        void *p = NULL;
+       dma_addr_t addr;
        ulong flags = 0;
 
        memset(&msg, 0, MAX_MESSAGE_SIZE*4);
@@ -1668,10 +1829,13 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
        }
        sg_offset = (msg[0]>>4)&0xf;
        msg[2] = 0x40000000; // IOCTL context
-       msg[3] = (u32)reply;
+       msg[3] = adpt_ioctl_to_context(pHba, reply);
+       if (msg[3] == (u32)-1)
+               return -EBUSY;
+
        memset(sg_list,0, sizeof(sg_list[0])*pHba->sg_tablesize);
        if(sg_offset) {
-               // TODO 64bit fix
+               // TODO add 64 bit API
                struct sg_simple_element *sg =  (struct sg_simple_element*) (msg+sg_offset);
                sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
                if (sg_count > pHba->sg_tablesize){
@@ -1690,7 +1854,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
                        }
                        sg_size = sg[i].flag_count & 0xffffff;      
                        /* Allocate memory for the transfer */
-                       p = kmalloc(sg_size, GFP_KERNEL|ADDR32);
+                       p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL);
                        if(!p) {
                                printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                                pHba->name,sg_size,i,sg_count);
@@ -1700,15 +1864,15 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
                        sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
                        /* Copy in the user's SG buffer if necessary */
                        if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
-                               // TODO 64bit fix
-                               if (copy_from_user(p,(void __user *)sg[i].addr_bus, sg_size)) {
+                               // sg_simple_element API is 32 bit
+                               if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) {
                                        printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i);
                                        rcode = -EFAULT;
                                        goto cleanup;
                                }
                        }
-                       //TODO 64bit fix
-                       sg[i].addr_bus = (u32)virt_to_bus(p);
+                       /* sg_simple_element API is 32 bit, but addr < 4GB */
+                       sg[i].addr_bus = addr;
                }
        }
 
@@ -1736,7 +1900,7 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
        if(sg_offset) {
        /* Copy back the Scatter Gather buffers back to user space */
                u32 j;
-               // TODO 64bit fix
+               // TODO add 64 bit API
                struct sg_simple_element* sg;
                int sg_size;
 
@@ -1756,14 +1920,14 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
                }
                sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
 
-               // TODO 64bit fix
+               // TODO add 64 bit API
                sg       = (struct sg_simple_element*)(msg + sg_offset);
                for (j = 0; j < sg_count; j++) {
                        /* Copy out the SG list to user's buffer if necessary */
                        if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
                                sg_size = sg[j].flag_count & 0xffffff; 
-                               // TODO 64bit fix
-                               if (copy_to_user((void __user *)sg[j].addr_bus,sg_list[j], sg_size)) {
+                               // sg_simple_element API is 32 bit
+                               if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) {
                                        printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus);
                                        rcode = -EFAULT;
                                        goto cleanup;
@@ -1787,12 +1951,17 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
 
 
 cleanup:
-       if (rcode != -ETIME && rcode != -EINTR)
+       if (rcode != -ETIME && rcode != -EINTR) {
+               struct sg_simple_element *sg =
+                               (struct sg_simple_element*) (msg +sg_offset);
                kfree (reply);
-       while(sg_index) {
-               if(sg_list[--sg_index]) {
-                       if (rcode != -ETIME && rcode != -EINTR)
-                               kfree(sg_list[sg_index]);
+               while(sg_index) {
+                       if(sg_list[--sg_index]) {
+                               dma_free_coherent(&pHba->pDev->dev,
+                                       sg[sg_index].flag_count & 0xffffff,
+                                       sg_list[sg_index],
+                                       sg[sg_index].addr_bus);
+                       }
                }
        }
        return rcode;
@@ -1978,6 +2147,38 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
        return error;
 }
 
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *file,
+                               unsigned int cmd, unsigned long arg)
+{
+       struct inode *inode;
+       long ret;
+       inode = file->f_dentry->d_inode;
+       lock_kernel();
+       switch(cmd) {
+               case DPT_SIGNATURE:
+               case I2OUSRCMD:
+               case DPT_CTRLINFO:
+               case DPT_SYSINFO:
+               case DPT_BLINKLED:
+               case I2ORESETCMD:
+               case I2ORESCANCMD:
+               case (DPT_TARGET_BUSY & 0xFFFF):
+               case DPT_TARGET_BUSY:
+                       ret = adpt_ioctl(inode, file, cmd, arg);
+                       break;
+               default:
+                       ret =  -ENOIOCTLCMD;
+       }
+       unlock_kernel();
+       return ret;
+}
+#endif
 
 static irqreturn_t adpt_isr(int irq, void *dev_id)
 {
@@ -2009,7 +2210,16 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
                                goto out;
                        }
                }
-               reply = bus_to_virt(m);
+               if (pHba->reply_pool_pa <= m &&
+                   m < pHba->reply_pool_pa +
+                       (pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4)) {
+                       reply = (u8 *)pHba->reply_pool +
+                                               (m - pHba->reply_pool_pa);
+               } else {
+                       /* Ick, we should *never* be here */
+                       printk(KERN_ERR "dpti: reply frame not from pool\n");
+                       reply = (u8 *)bus_to_virt(m);
+               }
 
                if (readl(reply) & MSG_FAIL) {
                        u32 old_m = readl(reply+28); 
@@ -2029,7 +2239,7 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
                } 
                context = readl(reply+8);
                if(context & 0x40000000){ // IOCTL
-                       void *p = (void *)readl(reply+12);
+                       void *p = adpt_ioctl_from_context(pHba, readl(reply+12));
                        if( p != NULL) {
                                memcpy_fromio(p, reply, REPLY_FRAME_SIZE * 4);
                        }
@@ -2043,15 +2253,17 @@ static irqreturn_t adpt_isr(int irq, void *dev_id)
                                status = I2O_POST_WAIT_OK;
                        }
                        if(!(context & 0x40000000)) {
-                               cmd = (struct scsi_cmnd*) readl(reply+12); 
+                               cmd = adpt_cmd_from_context(pHba,
+                                                       readl(reply+12));
                                if(cmd != NULL) {
                                        printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context);
                                }
                        }
                        adpt_i2o_post_wait_complete(context, status);
                } else { // SCSI message
-                       cmd = (struct scsi_cmnd*) readl(reply+12); 
+                       cmd = adpt_cmd_from_context (pHba, readl(reply+12));
                        if(cmd != NULL){
+                               scsi_dma_unmap(cmd);
                                if(cmd->serial_number != 0) { // If not timedout
                                        adpt_i2o_to_scsi(reply, cmd);
                                }
@@ -2072,6 +2284,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
        int i;
        u32 msg[MAX_MESSAGE_SIZE];
        u32* mptr;
+       u32* lptr;
        u32 *lenptr;
        int direction;
        int scsidir;
@@ -2079,6 +2292,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
        u32 len;
        u32 reqlen;
        s32 rcode;
+       dma_addr_t addr;
 
        memset(msg, 0 , sizeof(msg));
        len = scsi_bufflen(cmd);
@@ -2118,7 +2332,7 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
        // I2O_CMD_SCSI_EXEC
        msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid);
        msg[2] = 0;
-       msg[3] = (u32)cmd;      /* We want the SCSI control block back */
+       msg[3] = adpt_cmd_to_context(cmd);  /* Want SCSI control block back */
        // Our cards use the transaction context as the tag for queueing
        // Adaptec/DPT Private stuff 
        msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16);
@@ -2136,7 +2350,13 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
        memcpy(mptr, cmd->cmnd, cmd->cmd_len);
        mptr+=4;
        lenptr=mptr++;          /* Remember me - fill in when we know */
-       reqlen = 14;            // SINGLE SGE
+       if (dpt_dma64(pHba)) {
+               reqlen = 16;            // SINGLE SGE
+               *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+               *mptr++ = 1 << PAGE_SHIFT;
+       } else {
+               reqlen = 14;            // SINGLE SGE
+       }
        /* Now fill in the SGList and command */
 
        nseg = scsi_dma_map(cmd);
@@ -2146,12 +2366,16 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
 
                len = 0;
                scsi_for_each_sg(cmd, sg, nseg, i) {
+                       lptr = mptr;
                        *mptr++ = direction|0x10000000|sg_dma_len(sg);
                        len+=sg_dma_len(sg);
-                       *mptr++ = sg_dma_address(sg);
+                       addr = sg_dma_address(sg);
+                       *mptr++ = dma_low(addr);
+                       if (dpt_dma64(pHba))
+                               *mptr++ = dma_high(addr);
                        /* Make this an end of list */
                        if (i == nseg - 1)
-                               mptr[-2] = direction|0xD0000000|sg_dma_len(sg);
+                               *lptr = direction|0xD0000000|sg_dma_len(sg);
                }
                reqlen = mptr - msg;
                *lenptr = len;
@@ -2177,13 +2401,13 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
 }
 
 
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht)
 {
-       struct Scsi_Host *host = NULL;
+       struct Scsi_Host *host;
 
-       host = scsi_register(sht, sizeof(adpt_hba*));
+       host = scsi_host_alloc(sht, sizeof(adpt_hba*));
        if (host == NULL) {
-               printk ("%s: scsi_register returned NULL\n",pHba->name);
+               printk("%s: scsi_host_alloc returned NULL\n", pHba->name);
                return -1;
        }
        host->hostdata[0] = (unsigned long)pHba;
@@ -2200,7 +2424,7 @@ static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
        host->max_lun = 256;
        host->max_channel = pHba->top_scsi_channel + 1;
        host->cmd_per_lun = 1;
-       host->unique_id = (uint) pHba;
+       host->unique_id = (u32)sys_tbl_pa + pHba->unit;
        host->sg_tablesize = pHba->sg_tablesize;
        host->can_queue = pHba->post_fifo_size;
 
@@ -2640,11 +2864,10 @@ static s32 adpt_send_nop(adpt_hba*pHba,u32 m)
 static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
 {
        u8 *status;
+       dma_addr_t addr;
        u32 __iomem *msg = NULL;
        int i;
        ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ;
-       u32* ptr;
-       u32 outbound_frame;  // This had to be a 32 bit address
        u32 m;
 
        do {
@@ -2663,13 +2886,14 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
 
        msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
 
-       status = kzalloc(4, GFP_KERNEL|ADDR32);
+       status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
        if (!status) {
                adpt_send_nop(pHba, m);
                printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
                        pHba->name);
                return -ENOMEM;
        }
+       memset(status, 0, 4);
 
        writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
        writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
@@ -2678,7 +2902,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
        writel(4096, &msg[4]);          /* Host page frame size */
        writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]);   /* Outbound msg frame size and Initcode */
        writel(0xD0000004, &msg[6]);            /* Simple SG LE, EOB */
-       writel(virt_to_bus(status), &msg[7]);
+       writel((u32)addr, &msg[7]);
 
        writel(m, pHba->post_port);
        wmb();
@@ -2693,6 +2917,10 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
                rmb();
                if(time_after(jiffies,timeout)){
                        printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name);
+                       /* We lose 4 bytes of "status" here, but we
+                          cannot free these because controller may
+                          awake and corrupt those bytes at any time */
+                       /* dma_free_coherent(&pHba->pDev->dev, 4, status, addr); */
                        return -ETIMEDOUT;
                }
                schedule_timeout_uninterruptible(1);
@@ -2701,25 +2929,30 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
        // If the command was successful, fill the fifo with our reply
        // message packets
        if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) {
-               kfree(status);
+               dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
                return -2;
        }
-       kfree(status);
+       dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
 
-       kfree(pHba->reply_pool);
+       if(pHba->reply_pool != NULL) {
+               dma_free_coherent(&pHba->pDev->dev,
+                       pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+                       pHba->reply_pool, pHba->reply_pool_pa);
+       }
 
-       pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+       pHba->reply_pool = dma_alloc_coherent(&pHba->pDev->dev,
+                               pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+                               &pHba->reply_pool_pa, GFP_KERNEL);
        if (!pHba->reply_pool) {
                printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
                return -ENOMEM;
        }
+       memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
 
-       ptr = pHba->reply_pool;
        for(i = 0; i < pHba->reply_fifo_size; i++) {
-               outbound_frame = (u32)virt_to_bus(ptr);
-               writel(outbound_frame, pHba->reply_port);
+               writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4),
+                       pHba->reply_port);
                wmb();
-               ptr +=  REPLY_FRAME_SIZE;
        }
        adpt_i2o_status_get(pHba);
        return 0;
@@ -2743,11 +2976,11 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
        u32 m;
        u32 __iomem *msg;
        u8 *status_block=NULL;
-       ulong status_block_bus;
 
        if(pHba->status_block == NULL) {
-               pHba->status_block = (i2o_status_block*)
-                       kmalloc(sizeof(i2o_status_block),GFP_KERNEL|ADDR32);
+               pHba->status_block = dma_alloc_coherent(&pHba->pDev->dev,
+                                       sizeof(i2o_status_block),
+                                       &pHba->status_block_pa, GFP_KERNEL);
                if(pHba->status_block == NULL) {
                        printk(KERN_ERR
                        "dpti%d: Get Status Block failed; Out of memory. \n", 
@@ -2757,7 +2990,6 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
        }
        memset(pHba->status_block, 0, sizeof(i2o_status_block));
        status_block = (u8*)(pHba->status_block);
-       status_block_bus = virt_to_bus(pHba->status_block);
        timeout = jiffies+TMOUT_GETSTATUS*HZ;
        do {
                rmb();
@@ -2782,8 +3014,8 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
        writel(0, &msg[3]);
        writel(0, &msg[4]);
        writel(0, &msg[5]);
-       writel(((u32)status_block_bus)&0xffffffff, &msg[6]);
-       writel(0, &msg[7]);
+       writel( dma_low(pHba->status_block_pa), &msg[6]);
+       writel( dma_high(pHba->status_block_pa), &msg[7]);
        writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes
 
        //post message
@@ -2812,7 +3044,17 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba)
        }
 
        // Calculate the Scatter Gather list size
-       pHba->sg_tablesize = (pHba->status_block->inbound_frame_size * 4 -40)/ sizeof(struct sg_simple_element);
+       if (dpt_dma64(pHba)) {
+               pHba->sg_tablesize
+                 = ((pHba->status_block->inbound_frame_size * 4
+                 - 14 * sizeof(u32))
+                 / (sizeof(struct sg_simple_element) + sizeof(u32)));
+       } else {
+               pHba->sg_tablesize
+                 = ((pHba->status_block->inbound_frame_size * 4
+                 - 12 * sizeof(u32))
+                 / sizeof(struct sg_simple_element));
+       }
        if (pHba->sg_tablesize > SG_LIST_ELEMENTS) {
                pHba->sg_tablesize = SG_LIST_ELEMENTS;
        }
@@ -2863,7 +3105,9 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
        }
        do {
                if (pHba->lct == NULL) {
-                       pHba->lct = kmalloc(pHba->lct_size, GFP_KERNEL|ADDR32);
+                       pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
+                                       pHba->lct_size, &pHba->lct_pa,
+                                       GFP_KERNEL);
                        if(pHba->lct == NULL) {
                                printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
                                        pHba->name);
@@ -2879,7 +3123,7 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
                msg[4] = 0xFFFFFFFF;    /* All devices */
                msg[5] = 0x00000000;    /* Report now */
                msg[6] = 0xD0000000|pHba->lct_size;
-               msg[7] = virt_to_bus(pHba->lct);
+               msg[7] = (u32)pHba->lct_pa;
 
                if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) {
                        printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", 
@@ -2890,7 +3134,8 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
 
                if ((pHba->lct->table_size << 2) > pHba->lct_size) {
                        pHba->lct_size = pHba->lct->table_size << 2;
-                       kfree(pHba->lct);
+                       dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+                                       pHba->lct, pHba->lct_pa);
                        pHba->lct = NULL;
                }
        } while (pHba->lct == NULL);
@@ -2901,13 +3146,19 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
        // I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO;
        if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) {
                pHba->FwDebugBufferSize = buf[1];
-               pHba->FwDebugBuffer_P    = pHba->base_addr_virt + buf[0];
-               pHba->FwDebugFlags_P     = pHba->FwDebugBuffer_P + FW_DEBUG_FLAGS_OFFSET;
-               pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P + FW_DEBUG_BLED_OFFSET;
-               pHba->FwDebugBLEDflag_P  = pHba->FwDebugBLEDvalue_P + 1;
-               pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P + FW_DEBUG_STR_LENGTH_OFFSET;
-               pHba->FwDebugBuffer_P += buf[2]; 
-               pHba->FwDebugFlags = 0;
+               pHba->FwDebugBuffer_P = ioremap(pHba->base_addr_phys + buf[0],
+                                               pHba->FwDebugBufferSize);
+               if (pHba->FwDebugBuffer_P) {
+                       pHba->FwDebugFlags_P     = pHba->FwDebugBuffer_P +
+                                                       FW_DEBUG_FLAGS_OFFSET;
+                       pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P +
+                                                       FW_DEBUG_BLED_OFFSET;
+                       pHba->FwDebugBLEDflag_P  = pHba->FwDebugBLEDvalue_P + 1;
+                       pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P +
+                                               FW_DEBUG_STR_LENGTH_OFFSET;
+                       pHba->FwDebugBuffer_P += buf[2]; 
+                       pHba->FwDebugFlags = 0;
+               }
        }
 
        return 0;
@@ -2915,25 +3166,30 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
 
 static int adpt_i2o_build_sys_table(void)
 {
-       adpt_hba* pHba = NULL;
+       adpt_hba* pHba = hba_chain;
        int count = 0;
 
+       if (sys_tbl)
+               dma_free_coherent(&pHba->pDev->dev, sys_tbl_len,
+                                       sys_tbl, sys_tbl_pa);
+
        sys_tbl_len = sizeof(struct i2o_sys_tbl) +      // Header + IOPs
                                (hba_count) * sizeof(struct i2o_sys_tbl_entry);
 
-       kfree(sys_tbl);
-
-       sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+       sys_tbl = dma_alloc_coherent(&pHba->pDev->dev,
+                               sys_tbl_len, &sys_tbl_pa, GFP_KERNEL);
        if (!sys_tbl) {
                printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");     
                return -ENOMEM;
        }
+       memset(sys_tbl, 0, sys_tbl_len);
 
        sys_tbl->num_entries = hba_count;
        sys_tbl->version = I2OVERSION;
        sys_tbl->change_ind = sys_tbl_ind++;
 
        for(pHba = hba_chain; pHba; pHba = pHba->next) {
+               u64 addr;
                // Get updated Status Block so we have the latest information
                if (adpt_i2o_status_get(pHba)) {
                        sys_tbl->num_entries--;
@@ -2949,8 +3205,9 @@ static int adpt_i2o_build_sys_table(void)
                sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size;
                sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
                sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities;
-               sys_tbl->iops[count].inbound_low = (u32)virt_to_bus(pHba->post_port);
-               sys_tbl->iops[count].inbound_high = (u32)((u64)virt_to_bus(pHba->post_port)>>32);
+               addr = pHba->base_addr_phys + 0x40;
+               sys_tbl->iops[count].inbound_low = dma_low(addr);
+               sys_tbl->iops[count].inbound_high = dma_high(addr);
 
                count++;
        }
@@ -3086,7 +3343,8 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
 
        do {
                if (pHba->hrt == NULL) {
-                       pHba->hrt=kmalloc(size, GFP_KERNEL|ADDR32);
+                       pHba->hrt = dma_alloc_coherent(&pHba->pDev->dev,
+                                       size, &pHba->hrt_pa, GFP_KERNEL);
                        if (pHba->hrt == NULL) {
                                printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name);
                                return -ENOMEM;
@@ -3098,7 +3356,7 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
                msg[2]= 0;
                msg[3]= 0;
                msg[4]= (0xD0000000 | size);    /* Simple transaction */
-               msg[5]= virt_to_bus(pHba->hrt);   /* Dump it here */
+               msg[5]= (u32)pHba->hrt_pa;      /* Dump it here */
 
                if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) {
                        printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret);
@@ -3106,8 +3364,10 @@ static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
                }
 
                if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) {
-                       size = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
-                       kfree(pHba->hrt);
+                       int newsize = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
+                       dma_free_coherent(&pHba->pDev->dev, size,
+                               pHba->hrt, pHba->hrt_pa);
+                       size = newsize;
                        pHba->hrt = NULL;
                }
        } while(pHba->hrt == NULL);
@@ -3121,33 +3381,54 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
                        int group, int field, void *buf, int buflen)
 {
        u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
-       u8 *resblk;
+       u8 *opblk_va;
+       dma_addr_t opblk_pa;
+       u8 *resblk_va;
+       dma_addr_t resblk_pa;
 
        int size;
 
        /* 8 bytes for header */
-       resblk = kmalloc(sizeof(u8) * (8+buflen), GFP_KERNEL|ADDR32);
-       if (resblk == NULL) {
+       resblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+                       sizeof(u8) * (8 + buflen), &resblk_pa, GFP_KERNEL);
+       if (resblk_va == NULL) {
                printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name);
                return -ENOMEM;
        }
 
+       opblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+                       sizeof(opblk), &opblk_pa, GFP_KERNEL);
+       if (opblk_va == NULL) {
+               dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+                       resblk_va, resblk_pa);
+               printk(KERN_CRIT "%s: query operatio failed; Out of memory.\n",
+                       pHba->name);
+               return -ENOMEM;
+       }
        if (field == -1)                /* whole group */
                        opblk[4] = -1;
 
+       memcpy(opblk_va, opblk, sizeof(opblk));
        size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid, 
-               opblk, sizeof(opblk), resblk, sizeof(u8)*(8+buflen));
+               opblk_va, opblk_pa, sizeof(opblk),
+               resblk_va, resblk_pa, sizeof(u8)*(8+buflen));
+       dma_free_coherent(&pHba->pDev->dev, sizeof(opblk), opblk_va, opblk_pa);
        if (size == -ETIME) {
+               dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+                                                       resblk_va, resblk_pa);
                printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name);
                return -ETIME;
        } else if (size == -EINTR) {
+               dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+                                                       resblk_va, resblk_pa);
                printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name);
                return -EINTR;
        }
                        
-       memcpy(buf, resblk+8, buflen);  /* cut off header */
+       memcpy(buf, resblk_va+8, buflen);  /* cut off header */
 
-       kfree(resblk);
+       dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+                                               resblk_va, resblk_pa);
        if (size < 0)
                return size;    
 
@@ -3164,10 +3445,11 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
  *     ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
  */
 static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, 
-                 void *opblk, int oplen, void *resblk, int reslen)
+                 void *opblk_va,  dma_addr_t opblk_pa, int oplen,
+               void *resblk_va, dma_addr_t resblk_pa, int reslen)
 {
        u32 msg[9]; 
-       u32 *res = (u32 *)resblk;
+       u32 *res = (u32 *)resblk_va;
        int wait_status;
 
        msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
@@ -3176,12 +3458,12 @@ static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
        msg[3] = 0;
        msg[4] = 0;
        msg[5] = 0x54000000 | oplen;    /* OperationBlock */
-       msg[6] = virt_to_bus(opblk);
+       msg[6] = (u32)opblk_pa;
        msg[7] = 0xD0000000 | reslen;   /* ResultBlock */
-       msg[8] = virt_to_bus(resblk);
+       msg[8] = (u32)resblk_pa;
 
        if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) {
-               printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk);
+               printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk_va);
                return wait_status;     /* -DetailedStatus */
        }
 
@@ -3284,7 +3566,7 @@ static int adpt_i2o_systab_send(adpt_hba* pHba)
         * Private i/o space declaration  
         */
        msg[6] = 0x54000000 | sys_tbl_len;
-       msg[7] = virt_to_phys(sys_tbl);
+       msg[7] = (u32)sys_tbl_pa;
        msg[8] = 0x54000000 | 0;
        msg[9] = 0;
        msg[10] = 0xD4000000 | 0;
@@ -3323,11 +3605,10 @@ static static void adpt_delay(int millisec)
 #endif
 
 static struct scsi_host_template driver_template = {
+       .module                 = THIS_MODULE,
        .name                   = "dpt_i2o",
        .proc_name              = "dpt_i2o",
        .proc_info              = adpt_proc_info,
-       .detect                 = adpt_detect,
-       .release                = adpt_release,
        .info                   = adpt_info,
        .queuecommand           = adpt_queue,
        .eh_abort_handler       = adpt_abort,
@@ -3341,5 +3622,48 @@ static struct scsi_host_template driver_template = {
        .cmd_per_lun            = 1,
        .use_clustering         = ENABLE_CLUSTERING,
 };
-#include "scsi_module.c"
+
+static int __init adpt_init(void)
+{
+       int             error;
+       adpt_hba        *pHba, *next;
+
+       printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+
+       error = adpt_detect(&driver_template);
+       if (error < 0)
+               return error;
+       if (hba_chain == NULL)
+               return -ENODEV;
+
+       for (pHba = hba_chain; pHba; pHba = pHba->next) {
+               error = scsi_add_host(pHba->host, &pHba->pDev->dev);
+               if (error)
+                       goto fail;
+               scsi_scan_host(pHba->host);
+       }
+       return 0;
+fail:
+       for (pHba = hba_chain; pHba; pHba = next) {
+               next = pHba->next;
+               scsi_remove_host(pHba->host);
+       }
+       return error;
+}
+
+static void __exit adpt_exit(void)
+{
+       adpt_hba        *pHba, *next;
+
+       for (pHba = hba_chain; pHba; pHba = pHba->next)
+               scsi_remove_host(pHba->host);
+       for (pHba = hba_chain; pHba; pHba = next) {
+               next = pHba->next;
+               adpt_release(pHba->host);
+       }
+}
+
+module_init(adpt_init);
+module_exit(adpt_exit);
+
 MODULE_LICENSE("GPL");
index fd79068c586931b640eb2f1814b96eaa84bae76b..924cd5a51676a9b7212016722d6d319b60817608 100644 (file)
@@ -84,7 +84,6 @@ static int adpt_device_reset(struct scsi_cmnd* cmd);
 #define PCI_DPT_DEVICE_ID         (0xA501)     // DPT PCI I2O Device ID
 #define PCI_DPT_RAPTOR_DEVICE_ID  (0xA511)     
 
-//#define REBOOT_NOTIFIER 1
 /* Debugging macro from Linux Device Drivers - Rubini */
 #undef PDEBUG
 #ifdef DEBUG
@@ -229,14 +228,19 @@ typedef struct _adpt_hba {
        u32  post_fifo_size;
        u32  reply_fifo_size;
        u32* reply_pool;
+       dma_addr_t reply_pool_pa;
        u32  sg_tablesize;      // Scatter/Gather List Size.       
        u8  top_scsi_channel;
        u8  top_scsi_id;
        u8  top_scsi_lun;
+       u8  dma64;
 
        i2o_status_block* status_block;
+       dma_addr_t status_block_pa;
        i2o_hrt* hrt;
+       dma_addr_t hrt_pa;
        i2o_lct* lct;
+       dma_addr_t lct_pa;
        uint lct_size;
        struct i2o_device* devices;
        struct adpt_channel channel[MAX_CHANNEL];
@@ -249,6 +253,7 @@ typedef struct _adpt_hba {
        void __iomem *FwDebugBLEDflag_P;// Virtual Addr Of FW Debug BLED
        void __iomem *FwDebugBLEDvalue_P;// Virtual Addr Of FW Debug BLED
        u32 FwDebugFlags;
+       u32 *ioctl_reply_context[4];
 } adpt_hba;
 
 struct sg_simple_element {
@@ -264,9 +269,6 @@ static void adpt_i2o_sys_shutdown(void);
 static int adpt_init(void);
 static int adpt_i2o_build_sys_table(void);
 static irqreturn_t adpt_isr(int irq, void *dev_id);
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
-#endif
 
 static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d);
 static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid, 
@@ -275,7 +277,8 @@ static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
 static const char *adpt_i2o_get_class_name(int class);
 #endif
 static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, 
-                 void *opblk, int oplen, void *resblk, int reslen);
+                 void *opblk, dma_addr_t opblk_pa, int oplen,
+                 void *resblk, dma_addr_t resblk_pa, int reslen);
 static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout);
 static int adpt_i2o_lct_get(adpt_hba* pHba);
 static int adpt_i2o_parse_lct(adpt_hba* pHba);
@@ -289,7 +292,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba);
 static s32 adpt_i2o_hrt_get(adpt_hba* pHba);
 static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice);
 static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd);
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht);
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba,struct scsi_host_template * sht);
 static s32 adpt_hba_reset(adpt_hba* pHba);
 static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
 static s32 adpt_rescan(adpt_hba* pHba);
index c6d6e7c6559a6664008cbcf9fe75ae106577b476..8e2e964af6689c31c3c7c7c7d85a7a7bd477fe74 100644 (file)
@@ -465,7 +465,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
     scp->request = (struct request *)&wait;
     scp->timeout_per_command = timeout*HZ;
     scp->cmd_len = 12;
-    memcpy(scp->cmnd, cmnd, 12);
+    scp->cmnd = cmnd;
     cmndinfo.priority = IOCTL_PRI;
     cmndinfo.internal_cmd_str = gdtcmd;
     cmndinfo.internal_command = 1;
index 5b7be1e9841c23da55fd007390c90bbd237ff79a..aaa48e0c8ed054a231c1c2a3d699371be32f4d41 100644 (file)
@@ -763,9 +763,9 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
                        scp,
                        host->host_no, scp->device->channel,
                        scp->device->id, scp->device->lun,
-                       *((u32 *)&scp->cmnd),
-                       *((u32 *)&scp->cmnd + 1),
-                       *((u32 *)&scp->cmnd + 2),
+                       ((u32 *)scp->cmnd)[0],
+                       ((u32 *)scp->cmnd)[1],
+                       ((u32 *)scp->cmnd)[2],
                        _req->index, _req->req_virt);
 
        scp->result = 0;
index 4a922c57125ef1403e074d32eb85309c84002e6d..ccfd8aca3765875cf7cf4711aba0aa8bfbb6fb09 100644 (file)
@@ -686,7 +686,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
        }
        
        if (cmnd) {
-               cmnd->result = rsp->status;
+               cmnd->result |= rsp->status;
                if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
                        memcpy(cmnd->sense_buffer,
                               rsp->data,
@@ -730,6 +730,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        u16 lun = lun_from_dev(cmnd->device);
        u8 out_fmt, in_fmt;
 
+       cmnd->result = (DID_OK << 16);
        evt_struct = get_event_struct(&hostdata->pool);
        if (!evt_struct)
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -738,7 +739,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        srp_cmd = &evt_struct->iu.srp.cmd;
        memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
        srp_cmd->opcode = SRP_CMD;
-       memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+       memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
        srp_cmd->lun = ((u64) lun) << 48;
 
        if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
@@ -1347,6 +1348,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
 
        del_timer(&evt_struct->timer);
 
+       if (crq->status != VIOSRP_OK && evt_struct->cmnd)
+               evt_struct->cmnd->result = DID_ERROR << 16;
        if (evt_struct->done)
                evt_struct->done(evt_struct);
        else
index 90f1a61283adaeb527f038a193b4e635776a1057..4c4aadb3e405fa9f4e8a2d8a1aa6cf4cf438daf9 100644 (file)
@@ -59,6 +59,15 @@ enum viosrp_crq_formats {
        VIOSRP_INLINE_FORMAT = 0x07
 };
 
+enum viosrp_crq_status {
+       VIOSRP_OK = 0x0,
+       VIOSRP_NONRECOVERABLE_ERR = 0x1,
+       VIOSRP_VIOLATES_MAX_XFER = 0x2,
+       VIOSRP_PARTNER_PANIC = 0x3,
+       VIOSRP_DEVICE_BUSY = 0x8,
+       VIOSRP_ADAPTER_FAIL = 0x10
+};
+
 struct viosrp_crq {
        u8 valid;               /* used by RPA */
        u8 format;              /* SCSI vs out-of-band */
index dbae3fdb85065c92819443b0046c3fc81e5785a6..e3f739776bada819eb566bb2f8fcd861b7256519 100644 (file)
@@ -2590,7 +2590,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c
        cblk->hastat = 0;
        cblk->tastat = 0;
        /* Command the command */
-       memcpy(&cblk->cdb[0], &cmnd->cmnd, cmnd->cmd_len);
+       memcpy(cblk->cdb, cmnd->cmnd, cmnd->cmd_len);
 
        /* Set up tags */
        if (cmnd->device->tagged_supported) {   /* Tag Support                  */
index de5ae6a65029ffbd1efc31911ecf3d660e5f2320..999e91ea745139bba95caf0b9bd5224254ff9190 100644 (file)
@@ -2791,7 +2791,7 @@ static ssize_t ipr_store_adapter_state(struct device *dev,
 
 static struct device_attribute ipr_ioa_state_attr = {
        .attr = {
-               .name =         "state",
+               .name =         "online_state",
                .mode =         S_IRUGO | S_IWUSR,
        },
        .show = ipr_show_adapter_state,
index 820f91fb63ba55dcd4384e0fb4184744199d1deb..70a0f11f48b235d769b1efb088d1c9bd2c98f949 100644 (file)
@@ -3168,6 +3168,23 @@ megaraid_mbox_support_random_del(adapter_t *adapter)
        uint8_t         raw_mbox[sizeof(mbox_t)];
        int             rval;
 
+       /*
+        * Newer firmware on Dell CERC expect a different
+        * random deletion handling, so disable it.
+        */
+       if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI &&
+           adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 &&
+           adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+           adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH &&
+           (adapter->fw_version[0] > '6' ||
+            (adapter->fw_version[0] == '6' &&
+             adapter->fw_version[2] > '6') ||
+            (adapter->fw_version[0] == '6'
+             && adapter->fw_version[2] == '6'
+             && adapter->fw_version[3] > '1'))) {
+               con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n"));
+               return 0;
+       }
 
        mbox = (mbox_t *)raw_mbox;
 
index 626459d1e9021180c2af19e60576a85eeeb37772..c1d86d961a92df976c63da2dfa0cbd39d1babc52 100644 (file)
@@ -88,6 +88,7 @@
 #define PCI_SUBSYS_ID_PERC3_QC                         0x0471
 #define PCI_SUBSYS_ID_PERC3_DC                         0x0493
 #define PCI_SUBSYS_ID_PERC3_SC                         0x0475
+#define PCI_SUBSYS_ID_CERC_ATA100_4CH                  0x0511
 
 
 #define MBOX_MAX_SCSI_CMDS     128     // number of cmds reserved for kernel
index b937e9cddb2381608f2002320a18f82fc4729a55..7d84c8bbcf3fc1a55b8a9c04cbc65e2e05b33902 100644 (file)
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_sas.c
- * Version     : v00.00.03.16-rc1
+ * Version     : v00.00.03.20-rc1
  *
  * Authors:
  *     (email-id : megaraidlinux@lsi.com)
@@ -2650,12 +2650,13 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
        return;
 }
 
+#ifdef CONFIG_PM
 /**
  * megasas_suspend -   driver suspend entry point
  * @pdev:              PCI device structure
  * @state:             PCI power state to suspend routine
  */
-static int __devinit
+static int
 megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct Scsi_Host *host;
@@ -2687,7 +2688,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
  * megasas_resume-      driver resume entry point
  * @pdev:               PCI device structure
  */
-static int __devinit
+static int
 megasas_resume(struct pci_dev *pdev)
 {
        int rval;
@@ -2782,12 +2783,16 @@ fail_ready_state:
 
        return -ENODEV;
 }
+#else
+#define megasas_suspend        NULL
+#define megasas_resume NULL
+#endif
 
 /**
  * megasas_detach_one -        PCI hot"un"plug entry point
  * @pdev:              PCI device structure
  */
-static void megasas_detach_one(struct pci_dev *pdev)
+static void __devexit megasas_detach_one(struct pci_dev *pdev)
 {
        int i;
        struct Scsi_Host *host;
index 3a997eb457bf84813212c046beb08e73a51774cc..b0c41e67170281428b5725437524826a7a10fd6f 100644 (file)
@@ -18,9 +18,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.03.16-rc1"
-#define MEGASAS_RELDATE                                "Nov. 07, 2007"
-#define MEGASAS_EXT_VERSION                    "Thu. Nov. 07 10:09:32 PDT 2007"
+#define MEGASAS_VERSION                        "00.00.03.20-rc1"
+#define MEGASAS_RELDATE                        "March 10, 2008"
+#define MEGASAS_EXT_VERSION            "Mon. March 10 11:02:31 PDT 2008"
 
 /*
  * Device IDs
index e55b9037adb224286b4a2a0a1f0efd77a2b3b967..1dd70d7a4947c9a5f6ec41d5e46b3dc52a311f11 100644 (file)
@@ -2822,7 +2822,9 @@ static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
                dev_printk(KERN_DEBUG, &pdev->dev,
                        "phy[%d] Get Attached Address 0x%llX ,"
                        " SAS Address 0x%llX\n",
-                       i, phy->att_dev_sas_addr, phy->dev_sas_addr);
+                       i,
+                       (unsigned long long)phy->att_dev_sas_addr,
+                       (unsigned long long)phy->dev_sas_addr);
                dev_printk(KERN_DEBUG, &pdev->dev,
                        "Rate = %x , type = %d\n",
                        sas_phy->linkrate, phy->phy_type);
index ceab4f73caf1dfbaa953d91979ffedc937c7155f..c57c94c0ffd237f1d39b0cf6ea164e737ac11643 100644 (file)
@@ -8222,7 +8222,7 @@ static void process_waiting_list(struct ncb *np, int sts)
 #ifdef DEBUG_WAITING_LIST
        if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
 #endif
-       while (wcmd = waiting_list) {
+       while ((wcmd = waiting_list) != NULL) {
                waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd;
                wcmd->next_wcmd = NULL;
                if (sts == DID_OK) {
index 09ab3eac1c1abe9ac2e571e277cb3e1cfdfd4c8d..fa060932d2b4f632c486d59e4d436f79b1c349bb 100644 (file)
@@ -2858,7 +2858,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 
        /* Load SCSI command packet. */
        pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
-       memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+       memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
        /* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
 
        /* Set transfer direction. */
@@ -3127,7 +3127,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 
        /* Load SCSI command packet. */
        pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
-       memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+       memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
 
        /*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
        /* Set transfer direction. */
index 12d69d7c85775475ce89de8fc6a6381ba4453809..110e776d1a078cbd24cfdb795f7fec16cf95f1c3 100644 (file)
@@ -78,15 +78,6 @@ static void scsi_done(struct scsi_cmnd *cmd);
 /* Do not call reset on error if we just did a reset within 15 sec. */
 #define MIN_RESET_PERIOD (15*HZ)
 
-/*
- * Macro to determine the size of SCSI command. This macro takes vendor
- * unique commands into account. SCSI commands in groups 6 and 7 are
- * vendor unique and we will depend upon the command length being
- * supplied correctly in cmd_len.
- */
-#define CDB_SIZE(cmd)  (((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
-                               COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
-
 /*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
@@ -469,6 +460,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
        cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
        if (!cmd) {
                scsi_put_host_cmd_pool(gfp_mask);
+               shost->cmd_pool = NULL;
                return -ENOMEM;
        }
        list_add(&cmd->list, &shost->free_list);
@@ -481,6 +473,13 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
  */
 void scsi_destroy_command_freelist(struct Scsi_Host *shost)
 {
+       /*
+        * If cmd_pool is NULL the free list was not initialized, so
+        * do not attempt to release resources.
+        */
+       if (!shost->cmd_pool)
+               return;
+
        while (!list_empty(&shost->free_list)) {
                struct scsi_cmnd *cmd;
 
@@ -701,9 +700,11 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
         * Before we queue this command, check if the command
         * length exceeds what the host adapter can handle.
         */
-       if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
+       if (cmd->cmd_len > cmd->device->host->max_cmd_len) {
                SCSI_LOG_MLQUEUE(3,
-                               printk("queuecommand : command too long.\n"));
+                       printk("queuecommand : command too long. "
+                              "cdb_size=%d host->max_cmd_len=%d\n",
+                              cmd->cmd_len, cmd->device->host->max_cmd_len));
                cmd->result = (DID_ABORT << 16);
 
                scsi_done(cmd);
index 1eaba6cd80f411735b390a984a3f61837e377432..eaf5a8add1ba1a9ba9e03d8aaa0969ffd41d2c58 100644 (file)
@@ -626,7 +626,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
  * @scmd:       SCSI command structure to hijack
  * @ses:        structure to save restore information
  * @cmnd:       CDB to send. Can be NULL if no new cmnd is needed
- * @cmnd_size:  size in bytes of @cmnd
+ * @cmnd_size:  size in bytes of @cmnd (must be <= BLK_MAX_CDB)
  * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
  *
  * This function is used to save a scsi command information before re-execution
@@ -648,12 +648,14 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
         * command.
         */
        ses->cmd_len = scmd->cmd_len;
-       memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+       ses->cmnd = scmd->cmnd;
        ses->data_direction = scmd->sc_data_direction;
        ses->sdb = scmd->sdb;
        ses->next_rq = scmd->request->next_rq;
        ses->result = scmd->result;
 
+       scmd->cmnd = ses->eh_cmnd;
+       memset(scmd->cmnd, 0, BLK_MAX_CDB);
        memset(&scmd->sdb, 0, sizeof(scmd->sdb));
        scmd->request->next_rq = NULL;
 
@@ -665,14 +667,13 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
                scmd->sdb.table.sgl = &ses->sense_sgl;
                scmd->sc_data_direction = DMA_FROM_DEVICE;
                scmd->sdb.table.nents = 1;
-               memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
                scmd->cmnd[0] = REQUEST_SENSE;
                scmd->cmnd[4] = scmd->sdb.length;
                scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
        } else {
                scmd->sc_data_direction = DMA_NONE;
                if (cmnd) {
-                       memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+                       BUG_ON(cmnd_size > BLK_MAX_CDB);
                        memcpy(scmd->cmnd, cmnd, cmnd_size);
                        scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
                }
@@ -705,7 +706,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
         * Restore original data
         */
        scmd->cmd_len = ses->cmd_len;
-       memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+       scmd->cmnd = ses->cmnd;
        scmd->sc_data_direction = ses->data_direction;
        scmd->sdb = ses->sdb;
        scmd->request->next_rq = ses->next_rq;
@@ -1775,8 +1776,8 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
        scmd->request = &req;
        memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
-       memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
-    
+       scmd->cmnd = req.cmd;
+
        scmd->scsi_done         = scsi_reset_provider_done_command;
        memset(&scmd->sdb, 0, sizeof(scmd->sdb));
 
index d545ad1cf47a7f94c70369da8c1b6fb4dab0fe9d..a82d2fe80fb544da5afb86d835e6fbafb3a74533 100644 (file)
@@ -445,7 +445,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
        scsi_set_resid(cmd, 0);
        memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
        if (cmd->cmd_len == 0)
-               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+               cmd->cmd_len = scsi_command_size(cmd->cmnd);
 }
 
 void scsi_device_unbusy(struct scsi_device *sdev)
@@ -1094,6 +1094,8 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
        cmd->tag = req->tag;
        cmd->request = req;
 
+       cmd->cmnd = req->cmd;
+
        return cmd;
 }
 
@@ -1131,8 +1133,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
                req->buffer = NULL;
        }
 
-       BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
-       memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
        cmd->cmd_len = req->cmd_len;
        if (!req->data_len)
                cmd->sc_data_direction = DMA_NONE;
@@ -1169,6 +1169,7 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
        if (unlikely(!cmd))
                return BLKPREP_DEFER;
 
+       memset(cmd->cmnd, 0, BLK_MAX_CDB);
        return scsi_init_io(cmd, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(scsi_setup_fs_cmnd);
index ee8496aa0336682eedc40879dfca871d6551ff3c..257e097c39afe708e2e5a4286948e0de246c5c92 100644 (file)
@@ -107,6 +107,8 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
        cmd->jiffies_at_alloc = jiffies;
        cmd->request = rq;
 
+       cmd->cmnd = rq->cmd;
+
        rq->special = cmd;
        rq->cmd_type = REQ_TYPE_SPECIAL;
        rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
index 640333b1e75c9b32565bfeab8721ef566fb903c4..329eb8780e74f4c2335137acdd181e92d8c6e863 100644 (file)
@@ -744,7 +744,8 @@ static int wait_on_busy(unsigned long iobase, unsigned int loop) {
 static int board_inquiry(unsigned int j) {
    struct mscp *cpp;
    dma_addr_t id_dma_addr;
-   unsigned int time, limit = 0;
+   unsigned int limit = 0;
+   unsigned long time;
 
    id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,
                     sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);
@@ -1392,7 +1393,8 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
 }
 
 static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
-   unsigned int i, j, time, k, c, limit = 0;
+   unsigned int i, j, k, c, limit = 0;
+   unsigned long time;
    int arg_done = FALSE;
    struct scsi_cmnd *SCpnt;
 
index ea41f26264580dfe7a5ab27a71d19103305b7bc9..a1ca9b7bf2d5862b7466fbdcee4f5099b882ac76 100644 (file)
@@ -2271,7 +2271,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
                }
 
                if (up->port.flags & UPF_IOREMAP) {
-                       up->port.membase = ioremap(up->port.mapbase, size);
+                       up->port.membase = ioremap_nocache(up->port.mapbase,
+                                                                       size);
                        if (!up->port.membase) {
                                release_mem_region(up->port.mapbase, size);
                                ret = -ENOMEM;
index cd898704ba4f66d5fba055d4e9d574e5125786cd..f279745e9fefe9f07114923d58ebaec052dda4cf 100644 (file)
@@ -153,7 +153,7 @@ static int __init parse_options(struct early_serial8250_device *device,
                        (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
                port->membase += port->mapbase & ~PAGE_MASK;
 #else
-               port->membase = ioremap(port->mapbase, 64);
+               port->membase = ioremap_nocache(port->mapbase, 64);
                if (!port->membase) {
                        printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
                                __func__,
index 6e57382b9137504b1d9fdbb669610b9c37052376..53fa19cf2f0636d6dd79d0918266243441bda31f 100644 (file)
@@ -86,7 +86,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
                len =  pci_resource_len(dev, bar);
 
                if (!priv->remapped_bar[bar])
-                       priv->remapped_bar[bar] = ioremap(base, len);
+                       priv->remapped_bar[bar] = ioremap_nocache(base, len);
                if (!priv->remapped_bar[bar])
                        return -ENOMEM;
 
@@ -270,7 +270,7 @@ static int pci_plx9050_init(struct pci_dev *dev)
        /*
         * enable/disable interrupts
         */
-       p = ioremap(pci_resource_start(dev, 0), 0x80);
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
        if (p == NULL)
                return -ENOMEM;
        writel(irq_config, p + 0x4c);
@@ -294,7 +294,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
        /*
         * disable interrupts
         */
-       p = ioremap(pci_resource_start(dev, 0), 0x80);
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
        if (p != NULL) {
                writel(0, p + 0x4c);
 
@@ -341,7 +341,8 @@ static int sbs_init(struct pci_dev *dev)
 {
        u8 __iomem *p;
 
-       p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+       p = ioremap_nocache(pci_resource_start(dev, 0),
+                                               pci_resource_len(dev, 0));
 
        if (p == NULL)
                return -ENOMEM;
@@ -365,7 +366,8 @@ static void __devexit sbs_exit(struct pci_dev *dev)
 {
        u8 __iomem *p;
 
-       p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+       p = ioremap_nocache(pci_resource_start(dev, 0),
+                                       pci_resource_len(dev, 0));
        /* FIXME: What if resource_len < OCT_REG_CR_OFF */
        if (p != NULL)
                writeb(0, p + OCT_REG_CR_OFF);
@@ -419,7 +421,7 @@ static int pci_siig10x_init(struct pci_dev *dev)
                break;
        }
 
-       p = ioremap(pci_resource_start(dev, 0), 0x80);
+       p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
        if (p == NULL)
                return -ENOMEM;
 
index 12c934a1f2742c88a7b80e1b3ed00588d73e521b..8871aaa3dba677350f519280a5d75b8ff915316d 100644 (file)
@@ -373,6 +373,7 @@ struct neo_uart_struct {
 #define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME                "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
 #define PCI_DEVICE_NEO_2RJ45_PCI_NAME          "Neo 2 - RJ45 Universal PCI"
 #define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME       "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCIE_DEVICE_NEO_IBM_PCI_NAME           "Neo 4 - PCI Express - IBM"
 
 /*
  * Our Global Variables.
index 6767ee381cd1b4645056012ba3704c05177389a0..338cf8a08b436db85c1b9d11b10b2f868e93fd24 100644 (file)
@@ -82,7 +82,10 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* store the info for the board we've found */
        brd->boardnum = adapter_count++;
        brd->pci_dev = pdev;
-       brd->maxports = 2;
+       if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
+               brd->maxports = 4;
+       else
+               brd->maxports = 2;
 
        spin_lock_init(&brd->bd_lock);
        spin_lock_init(&brd->bd_intr_lock);
@@ -208,6 +211,7 @@ static struct pci_device_id jsm_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
        { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
        { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
index a9ac1fdb30948c5eba8ff864d0ee156d8db7e247..7fea3cf4588a37fa89589c8931862e704a62f156 100644 (file)
@@ -608,6 +608,7 @@ static void pump_transfers(unsigned long data)
        u8 width;
        u16 cr, dma_width, dma_config;
        u32 tranf_success = 1;
+       u8 full_duplex = 0;
 
        /* Get current state information */
        message = drv_data->cur_msg;
@@ -658,6 +659,7 @@ static void pump_transfers(unsigned long data)
        }
 
        if (transfer->rx_buf != NULL) {
+               full_duplex = transfer->tx_buf != NULL;
                drv_data->rx = transfer->rx_buf;
                drv_data->rx_end = drv_data->rx + transfer->len;
                dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
@@ -740,7 +742,8 @@ static void pump_transfers(unsigned long data)
         * successful use different way to r/w according to
         * drv_data->cur_chip->enable_dma
         */
-       if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
+       if (!full_duplex && drv_data->cur_chip->enable_dma
+                               && drv_data->len > 6) {
 
                disable_dma(drv_data->dma_channel);
                clear_dma_irqstat(drv_data->dma_channel);
@@ -828,7 +831,7 @@ static void pump_transfers(unsigned long data)
                /* IO mode write then read */
                dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
 
-               if (drv_data->tx != NULL && drv_data->rx != NULL) {
+               if (full_duplex) {
                        /* full duplex mode */
                        BUG_ON((drv_data->tx_end - drv_data->tx) !=
                               (drv_data->rx_end - drv_data->rx));
index 34bfb7dd77642f8a14a82bbca20ef2a2ef752456..0885cc357a371552dc2190a6da682f98a652abdb 100644 (file)
@@ -125,10 +125,10 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi,
        /* is clk = pclk / (2 * (pre+1)), or is it
         *    clk = (pclk * 2) / ( pre + 1) */
 
-       div = (div / 2) - 1;
+       div /= 2;
 
-       if (div < 0)
-               div = 1;
+       if (div > 0)
+               div -= 1;
 
        if (div > 255)
                div = 255;
index 516a6400db432eb0ccb6e96d7af7d0a0a3d0bb82..a419c42e880e208f5eec222fff067a7bbe7424c3 100644 (file)
@@ -17,6 +17,8 @@ obj-$(CONFIG_USB_SL811_HCD)   += host/
 obj-$(CONFIG_USB_U132_HCD)     += host/
 obj-$(CONFIG_USB_R8A66597_HCD) += host/
 
+obj-$(CONFIG_USB_C67X00_HCD)   += c67x00/
+
 obj-$(CONFIG_USB_ACM)          += class/
 obj-$(CONFIG_USB_PRINTER)      += class/
 
index 86e64035edb01b04ec7439c1c450bad641a14085..be0b8daac9c7de2681191161415877cb3289961e 100644 (file)
@@ -19,7 +19,6 @@ if USB_ATM
 
 config USB_SPEEDTOUCH
        tristate "Speedtouch USB support"
-       depends on USB_ATM
        select FW_LOADER
        help
          Say Y here if you have an SpeedTouch USB or SpeedTouch 330
@@ -32,7 +31,6 @@ config USB_SPEEDTOUCH
 
 config USB_CXACRU
        tristate "Conexant AccessRunner USB support"
-       depends on USB_ATM
        select FW_LOADER
        help
          Say Y here if you have an ADSL USB modem based on the Conexant
@@ -45,7 +43,6 @@ config USB_CXACRU
 
 config USB_UEAGLEATM
        tristate "ADI 930 and eagle USB DSL modem"
-       depends on USB_ATM
        select FW_LOADER
        help
          Say Y here if you have an ADSL USB modem based on the ADI 930
@@ -58,7 +55,6 @@ config USB_UEAGLEATM
 
 config USB_XUSBATM
        tristate "Other USB DSL modem support"
-       depends on USB_ATM
        help
          Say Y here if you have a DSL USB modem not explicitly supported by
          another USB DSL drivers.  In order to use your modem you will need to
diff --git a/drivers/usb/c67x00/Makefile b/drivers/usb/c67x00/Makefile
new file mode 100644 (file)
index 0000000..868bc41
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for Cypress C67X00 USB Controller
+#
+
+ccflags-$(CONFIG_USB_DEBUG)            += -DDEBUG
+
+obj-$(CONFIG_USB_C67X00_HCD)           += c67x00.o
+
+c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
new file mode 100644 (file)
index 0000000..5633bc5
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * c67x00-drv.c: Cypress C67X00 USB Common infrastructure
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+/*
+ * This file implements the common infrastructure for using the c67x00.
+ * It is both the link between the platform configuration and subdrivers and
+ * the link between the common hardware parts and the subdrivers (e.g.
+ * interrupt handling).
+ *
+ * The c67x00 has 2 SIE's (serial interface engine) wich can be configured
+ * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG).
+ *
+ * Depending on the platform configuration, the SIE's are created and
+ * the corresponding subdriver is initialized (c67x00_probe_sie).
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/usb/c67x00.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+static void c67x00_probe_sie(struct c67x00_sie *sie,
+                            struct c67x00_device *dev, int sie_num)
+{
+       spin_lock_init(&sie->lock);
+       sie->dev = dev;
+       sie->sie_num = sie_num;
+       sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num);
+
+       switch (sie->mode) {
+       case C67X00_SIE_HOST:
+               c67x00_hcd_probe(sie);
+               break;
+
+       case C67X00_SIE_UNUSED:
+               dev_info(sie_dev(sie),
+                        "Not using SIE %d as requested\n", sie->sie_num);
+               break;
+
+       default:
+               dev_err(sie_dev(sie),
+                       "Unsupported configuration: 0x%x for SIE %d\n",
+                       sie->mode, sie->sie_num);
+               break;
+       }
+}
+
+static void c67x00_remove_sie(struct c67x00_sie *sie)
+{
+       switch (sie->mode) {
+       case C67X00_SIE_HOST:
+               c67x00_hcd_remove(sie);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static irqreturn_t c67x00_irq(int irq, void *__dev)
+{
+       struct c67x00_device *c67x00 = __dev;
+       struct c67x00_sie *sie;
+       u16 msg, int_status;
+       int i, count = 8;
+
+       int_status = c67x00_ll_hpi_status(c67x00);
+       if (!int_status)
+               return IRQ_NONE;
+
+       while (int_status != 0 && (count-- >= 0)) {
+               c67x00_ll_irq(c67x00, int_status);
+               for (i = 0; i < C67X00_SIES; i++) {
+                       sie = &c67x00->sie[i];
+                       msg = 0;
+                       if (int_status & SIEMSG_FLG(i))
+                               msg = c67x00_ll_fetch_siemsg(c67x00, i);
+                       if (sie->irq)
+                               sie->irq(sie, int_status, msg);
+               }
+               int_status = c67x00_ll_hpi_status(c67x00);
+       }
+
+       if (int_status)
+               dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! "
+                        "status = 0x%04x\n", int_status);
+
+       return IRQ_HANDLED;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit c67x00_drv_probe(struct platform_device *pdev)
+{
+       struct c67x00_device *c67x00;
+       struct c67x00_platform_data *pdata;
+       struct resource *res, *res2;
+       int ret, i;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res2)
+               return -ENODEV;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata)
+               return -ENODEV;
+
+       c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL);
+       if (!c67x00)
+               return -ENOMEM;
+
+       if (!request_mem_region(res->start, res->end - res->start + 1,
+                               pdev->name)) {
+               dev_err(&pdev->dev, "Memory region busy\n");
+               ret = -EBUSY;
+               goto request_mem_failed;
+       }
+       c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
+       if (!c67x00->hpi.base) {
+               dev_err(&pdev->dev, "Unable to map HPI registers\n");
+               ret = -EIO;
+               goto map_failed;
+       }
+
+       spin_lock_init(&c67x00->hpi.lock);
+       c67x00->hpi.regstep = pdata->hpi_regstep;
+       c67x00->pdata = pdev->dev.platform_data;
+       c67x00->pdev = pdev;
+
+       c67x00_ll_init(c67x00);
+       c67x00_ll_hpi_reg_init(c67x00);
+
+       ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot claim IRQ\n");
+               goto request_irq_failed;
+       }
+
+       ret = c67x00_ll_reset(c67x00);
+       if (ret) {
+               dev_err(&pdev->dev, "Device reset failed\n");
+               goto reset_failed;
+       }
+
+       for (i = 0; i < C67X00_SIES; i++)
+               c67x00_probe_sie(&c67x00->sie[i], c67x00, i);
+
+       platform_set_drvdata(pdev, c67x00);
+
+       return 0;
+
+ reset_failed:
+       free_irq(res2->start, c67x00);
+ request_irq_failed:
+       iounmap(c67x00->hpi.base);
+ map_failed:
+       release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+       kfree(c67x00);
+
+       return ret;
+}
+
+static int __devexit c67x00_drv_remove(struct platform_device *pdev)
+{
+       struct c67x00_device *c67x00 = platform_get_drvdata(pdev);
+       struct resource *res;
+       int i;
+
+       for (i = 0; i < C67X00_SIES; i++)
+               c67x00_remove_sie(&c67x00->sie[i]);
+
+       c67x00_ll_release(c67x00);
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res)
+               free_irq(res->start, c67x00);
+
+       iounmap(c67x00->hpi.base);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               release_mem_region(res->start, res->end - res->start + 1);
+
+       kfree(c67x00);
+
+       return 0;
+}
+
+static struct platform_driver c67x00_driver = {
+       .probe  = c67x00_drv_probe,
+       .remove = __devexit_p(c67x00_drv_remove),
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "c67x00",
+       },
+};
+MODULE_ALIAS("platform:c67x00");
+
+static int __init c67x00_init(void)
+{
+       return platform_driver_register(&c67x00_driver);
+}
+
+static void __exit c67x00_exit(void)
+{
+       platform_driver_unregister(&c67x00_driver);
+}
+
+module_init(c67x00_init);
+module_exit(c67x00_exit);
+
+MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
+MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c
new file mode 100644 (file)
index 0000000..a22b887
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/* --------------------------------------------------------------------------
+ * Root Hub Support
+ */
+
+static __u8 c67x00_hub_des[] = {
+       0x09,                   /*  __u8  bLength; */
+       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
+       0x02,                   /*  __u8  bNbrPorts; */
+       0x00,                   /* __u16  wHubCharacteristics; */
+       0x00,                   /*   (per-port OC, no power switching) */
+       0x32,                   /*  __u8  bPwrOn2pwrGood; 2ms */
+       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
+       0x00,                   /*  __u8  DeviceRemovable; ** 7 Ports max ** */
+       0xff,                   /*  __u8  PortPwrCtrlMask; ** 7 ports max ** */
+};
+
+static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port)
+{
+       struct c67x00_hcd *c67x00 = sie->private_data;
+       unsigned long flags;
+
+       c67x00_ll_husb_reset(sie, port);
+
+       spin_lock_irqsave(&c67x00->lock, flags);
+       c67x00_ll_husb_reset_port(sie, port);
+       spin_unlock_irqrestore(&c67x00->lock, flags);
+
+       c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT);
+}
+
+static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+       struct c67x00_sie *sie = c67x00->sie;
+       u16 status;
+       int i;
+
+       *buf = 0;
+       status = c67x00_ll_usb_get_status(sie);
+       for (i = 0; i < C67X00_PORTS; i++)
+               if (status & PORT_CONNECT_CHANGE(i))
+                       *buf |= (1 << i);
+
+       /* bit 0 denotes hub change, b1..n port change */
+       *buf <<= 1;
+
+       return !!*buf;
+}
+
+static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+                             u16 wIndex, char *buf, u16 wLength)
+{
+       struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+       struct c67x00_sie *sie = c67x00->sie;
+       u16 status, usb_status;
+       int len = 0;
+       unsigned int port = wIndex-1;
+       u16 wPortChange, wPortStatus;
+
+       switch (typeReq) {
+
+       case GetHubStatus:
+               *(__le32 *) buf = cpu_to_le32(0);
+               len = 4;                /* hub power */
+               break;
+
+       case GetPortStatus:
+               if (wIndex > C67X00_PORTS)
+                       return -EPIPE;
+
+               status = c67x00_ll_usb_get_status(sie);
+               usb_status = c67x00_ll_get_usb_ctl(sie);
+
+               wPortChange = 0;
+               if (status & PORT_CONNECT_CHANGE(port))
+                       wPortChange |= USB_PORT_STAT_C_CONNECTION;
+
+               wPortStatus = USB_PORT_STAT_POWER;
+               if (!(status & PORT_SE0_STATUS(port)))
+                       wPortStatus |= USB_PORT_STAT_CONNECTION;
+               if (usb_status & LOW_SPEED_PORT(port)) {
+                       wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+                       c67x00->low_speed_ports |= (1 << port);
+               } else
+                       c67x00->low_speed_ports &= ~(1 << port);
+
+               if (usb_status & SOF_EOP_EN(port))
+                       wPortStatus |= USB_PORT_STAT_ENABLE;
+
+               *(__le16 *) buf = cpu_to_le16(wPortStatus);
+               *(__le16 *) (buf + 2) = cpu_to_le16(wPortChange);
+               len = 4;
+               break;
+
+       case SetHubFeature:     /* We don't implement these */
+       case ClearHubFeature:
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+               case C_HUB_LOCAL_POWER:
+                       len = 0;
+                       break;
+
+               default:
+                       return -EPIPE;
+               }
+               break;
+
+       case SetPortFeature:
+               if (wIndex > C67X00_PORTS)
+                       return -EPIPE;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "SetPortFeature %d (SUSPEND)\n", port);
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_RESET:
+                       c67x00_hub_reset_host_port(sie, port);
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_POWER:
+                       /* Power always enabled */
+                       len = 0;
+                       break;
+
+               default:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "%s: SetPortFeature %d (0x%04x) Error!\n",
+                               __func__, port, wValue);
+                       return -EPIPE;
+               }
+               break;
+
+       case ClearPortFeature:
+               if (wIndex > C67X00_PORTS)
+                       return -EPIPE;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       /* Reset the port so that the c67x00 also notices the
+                        * disconnect */
+                       c67x00_hub_reset_host_port(sie, port);
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_ENABLE:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "ClearPortFeature (%d): C_ENABLE\n", port);
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_SUSPEND:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "ClearPortFeature (%d): SUSPEND\n", port);
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_SUSPEND:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "ClearPortFeature (%d): C_SUSPEND\n", port);
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_POWER:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "ClearPortFeature (%d): POWER\n", port);
+                       return -EPIPE;
+
+               case USB_PORT_FEAT_C_CONNECTION:
+                       c67x00_ll_usb_clear_status(sie,
+                                                  PORT_CONNECT_CHANGE(port));
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "ClearPortFeature (%d): OVER_CURRENT\n", port);
+                       len = 0;
+                       break;
+
+               case USB_PORT_FEAT_C_RESET:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "ClearPortFeature (%d): C_RESET\n", port);
+                       len = 0;
+                       break;
+
+               default:
+                       dev_dbg(c67x00_hcd_dev(c67x00),
+                               "%s: ClearPortFeature %d (0x%04x) Error!\n",
+                               __func__, port, wValue);
+                       return -EPIPE;
+               }
+               break;
+
+       case GetHubDescriptor:
+               len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength);
+               memcpy(buf, c67x00_hub_des, len);
+               break;
+
+       default:
+               dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__);
+               return -EPIPE;
+       }
+
+       return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Main part of host controller driver
+ */
+
+/**
+ * c67x00_hcd_irq
+ *
+ * This function is called from the interrupt handler in c67x00-drv.c
+ */
+static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
+{
+       struct c67x00_hcd *c67x00 = sie->private_data;
+       struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+       /* Handle sie message flags */
+       if (msg) {
+               if (msg & HUSB_TDListDone)
+                       c67x00_sched_kick(c67x00);
+               else
+                       dev_warn(c67x00_hcd_dev(c67x00),
+                                "Unknown SIE msg flag(s): 0x%04x\n", msg);
+       }
+
+       if (unlikely(hcd->state == HC_STATE_HALT))
+               return;
+
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+               return;
+
+       /* Handle Start of frame events */
+       if (int_status & SOFEOP_FLG(sie->sie_num)) {
+               c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
+               c67x00_sched_kick(c67x00);
+               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+       }
+}
+
+/**
+ * c67x00_hcd_start: Host controller start hook
+ */
+static int c67x00_hcd_start(struct usb_hcd *hcd)
+{
+       hcd->uses_new_polling = 1;
+       hcd->state = HC_STATE_RUNNING;
+       hcd->poll_rh = 1;
+
+       return 0;
+}
+
+/**
+ * c67x00_hcd_stop: Host controller stop hook
+ */
+static void c67x00_hcd_stop(struct usb_hcd *hcd)
+{
+       /* Nothing to do */
+}
+
+static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
+{
+       struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+       u16 temp_val;
+
+       dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__);
+       temp_val = c67x00_ll_husb_get_frame(c67x00->sie);
+       temp_val &= HOST_FRAME_MASK;
+       return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;
+}
+
+static struct hc_driver c67x00_hc_driver = {
+       .description    = "c67x00-hcd",
+       .product_desc   = "Cypress C67X00 Host Controller",
+       .hcd_priv_size  = sizeof(struct c67x00_hcd),
+       .flags          = HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start          = c67x00_hcd_start,
+       .stop           = c67x00_hcd_stop,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue    = c67x00_urb_enqueue,
+       .urb_dequeue    = c67x00_urb_dequeue,
+       .endpoint_disable = c67x00_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = c67x00_hcd_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = c67x00_hub_status_data,
+       .hub_control    = c67x00_hub_control,
+};
+
+/* ---------------------------------------------------------------------
+ * Setup/Teardown routines
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie)
+{
+       struct c67x00_hcd *c67x00;
+       struct usb_hcd *hcd;
+       unsigned long flags;
+       int retval;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie");
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto err0;
+       }
+       c67x00 = hcd_to_c67x00_hcd(hcd);
+
+       spin_lock_init(&c67x00->lock);
+       c67x00->sie = sie;
+
+       INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]);
+       INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]);
+       INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]);
+       INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]);
+       c67x00->urb_count = 0;
+       INIT_LIST_HEAD(&c67x00->td_list);
+       c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num);
+       c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num);
+       c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+
+       c67x00_ll_husb_init_host_port(sie);
+
+       init_completion(&c67x00->endpoint_disable);
+       retval = c67x00_sched_start_scheduler(c67x00);
+       if (retval)
+               goto err1;
+
+       retval = usb_add_hcd(hcd, 0, 0);
+       if (retval) {
+               dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n",
+                       __func__, retval);
+               goto err2;
+       }
+
+       spin_lock_irqsave(&sie->lock, flags);
+       sie->private_data = c67x00;
+       sie->irq = c67x00_hcd_irq;
+       spin_unlock_irqrestore(&sie->lock, flags);
+
+       return retval;
+
+ err2:
+       c67x00_sched_stop_scheduler(c67x00);
+ err1:
+       usb_put_hcd(hcd);
+ err0:
+       return retval;
+}
+
+/* may be called with controller, bus, and devices active */
+void c67x00_hcd_remove(struct c67x00_sie *sie)
+{
+       struct c67x00_hcd *c67x00 = sie->private_data;
+       struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+       c67x00_sched_stop_scheduler(c67x00);
+       usb_remove_hcd(hcd);
+       usb_put_hcd(hcd);
+}
diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h
new file mode 100644 (file)
index 0000000..e8c6d94
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * c67x00-hcd.h: Cypress C67X00 USB HCD
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#ifndef _USB_C67X00_HCD_H
+#define _USB_C67X00_HCD_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include "../core/hcd.h"
+#include "c67x00.h"
+
+/*
+ * The following parameters depend on the CPU speed, bus speed, ...
+ * These can be tuned for specific use cases, e.g. if isochronous transfers
+ * are very important, bandwith can be sacrificed to guarantee that the
+ * 1ms deadline will be met.
+ * If bulk transfers are important, the MAX_FRAME_BW can be increased,
+ * but some (or many) isochronous deadlines might not be met.
+ *
+ * The values are specified in bittime.
+ */
+
+/*
+ * The current implementation switches between _STD (default) and _ISO (when
+ * isochronous transfers are scheduled), in order to optimize the throughput
+ * in normal cicrumstances, but also provide good isochronous behaviour.
+ *
+ * Bandwidth is described in bit time so with a 12MHz USB clock and 1ms
+ * frames; there are 12000 bit times per frame.
+ */
+
+#define TOTAL_FRAME_BW         12000
+#define DEFAULT_EOT            2250
+
+#define MAX_FRAME_BW_STD       (TOTAL_FRAME_BW - DEFAULT_EOT)
+#define MAX_FRAME_BW_ISO       2400
+
+/*
+ * Periodic transfers may only use 90% of the full frame, but as
+ * we currently don't even use 90% of the full frame, we may
+ * use the full usable time for periodic transfers.
+ */
+#define MAX_PERIODIC_BW(full_bw)       full_bw
+
+/* -------------------------------------------------------------------------- */
+
+struct c67x00_hcd {
+       spinlock_t lock;
+       struct c67x00_sie *sie;
+       unsigned int low_speed_ports;   /* bitmask of low speed ports */
+       unsigned int urb_count;
+       unsigned int urb_iso_count;
+
+       struct list_head list[4];       /* iso, int, ctrl, bulk */
+#if PIPE_BULK != 3
+#error "Sanity check failed, this code presumes PIPE_... to range from 0 to 3"
+#endif
+
+       /* USB bandwidth allocated to td_list */
+       int bandwidth_allocated;
+       /* USB bandwidth allocated for isoc/int transfer */
+       int periodic_bw_allocated;
+       struct list_head td_list;
+       int max_frame_bw;
+
+       u16 td_base_addr;
+       u16 buf_base_addr;
+       u16 next_td_addr;
+       u16 next_buf_addr;
+
+       struct tasklet_struct tasklet;
+
+       struct completion endpoint_disable;
+
+       u16 current_frame;
+       u16 last_frame;
+};
+
+static inline struct c67x00_hcd *hcd_to_c67x00_hcd(struct usb_hcd *hcd)
+{
+       return (struct c67x00_hcd *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00)
+{
+       return container_of((void *)c67x00, struct usb_hcd, hcd_priv);
+}
+
+/* ---------------------------------------------------------------------
+ * Functions used by c67x00-drv
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie);
+void c67x00_hcd_remove(struct c67x00_sie *sie);
+
+/* ---------------------------------------------------------------------
+ * Transfer Descriptor scheduling functions
+ */
+int c67x00_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+void c67x00_endpoint_disable(struct usb_hcd *hcd,
+                            struct usb_host_endpoint *ep);
+
+void c67x00_hcd_msg_received(struct c67x00_sie *sie, u16 msg);
+void c67x00_sched_kick(struct c67x00_hcd *c67x00);
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00);
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00);
+
+#define c67x00_hcd_dev(x)      (c67x00_hcd_to_hcd(x)->self.controller)
+
+#endif                         /* _USB_C67X00_HCD_H */
diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c
new file mode 100644 (file)
index 0000000..f3430b3
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/usb/c67x00.h>
+#include "c67x00.h"
+
+#define COMM_REGS 14
+
+struct c67x00_lcp_int_data {
+       u16 regs[COMM_REGS];
+};
+
+/* -------------------------------------------------------------------------- */
+/* Interface definitions */
+
+#define COMM_ACK                       0x0FED
+#define COMM_NAK                       0xDEAD
+
+#define COMM_RESET                     0xFA50
+#define COMM_EXEC_INT                  0xCE01
+#define COMM_INT_NUM                   0x01C2
+
+/* Registers 0 to COMM_REGS-1 */
+#define COMM_R(x)                      (0x01C4 + 2 * (x))
+
+#define HUSB_SIE_pCurrentTDPtr(x)      ((x) ? 0x01B2 : 0x01B0)
+#define HUSB_SIE_pTDListDone_Sem(x)    ((x) ? 0x01B8 : 0x01B6)
+#define HUSB_pEOT                      0x01B4
+
+/* Software interrupts */
+/* 114, 115: */
+#define HUSB_SIE_INIT_INT(x)           ((x) ? 0x0073 : 0x0072)
+#define HUSB_RESET_INT                 0x0074
+
+#define SUSB_INIT_INT                  0x0071
+#define SUSB_INIT_INT_LOC              (SUSB_INIT_INT * 2)
+
+/* -----------------------------------------------------------------------
+ * HPI implementation
+ *
+ * The c67x00 chip also support control via SPI or HSS serial
+ * interfaces.  However, this driver assumes that register access can
+ * be performed from IRQ context.  While this is a safe assuption with
+ * the HPI interface, it is not true for the serial interfaces.
+ */
+
+/* HPI registers */
+#define HPI_DATA       0
+#define HPI_MAILBOX    1
+#define HPI_ADDR       2
+#define HPI_STATUS     3
+
+static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
+{
+       return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
+{
+       __raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
+{
+       hpi_write_reg(dev, HPI_ADDR, reg);
+       return hpi_read_reg(dev, HPI_DATA);
+}
+
+static u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
+{
+       u16 value;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       value = hpi_read_word_nolock(dev, reg);
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+       return value;
+}
+
+static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
+{
+       hpi_write_reg(dev, HPI_ADDR, reg);
+       hpi_write_reg(dev, HPI_DATA, value);
+}
+
+static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       hpi_write_word_nolock(dev, reg, value);
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
+                                u16 *data, u16 count)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+
+       hpi_write_reg(dev, HPI_ADDR, addr);
+       for (i = 0; i < count; i++)
+               hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
+
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
+                               u16 *data, u16 count)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       hpi_write_reg(dev, HPI_ADDR, addr);
+       for (i = 0; i < count; i++)
+               *data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
+
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+       u16 value;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       value = hpi_read_word_nolock(dev, reg);
+       hpi_write_word_nolock(dev, reg, value | mask);
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+       u16 value;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       value = hpi_read_word_nolock(dev, reg);
+       hpi_write_word_nolock(dev, reg, value & ~mask);
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static u16 hpi_recv_mbox(struct c67x00_device *dev)
+{
+       u16 value;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       value = hpi_read_reg(dev, HPI_MAILBOX);
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+       return value;
+}
+
+static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       hpi_write_reg(dev, HPI_MAILBOX, value);
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+       return value;
+}
+
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
+{
+       u16 value;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->hpi.lock, flags);
+       value = hpi_read_reg(dev, HPI_STATUS);
+       spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+       return value;
+}
+
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
+{
+       int i;
+
+       hpi_recv_mbox(dev);
+       c67x00_ll_hpi_status(dev);
+       hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
+
+       for (i = 0; i < C67X00_SIES; i++) {
+               hpi_write_word(dev, SIEMSG_REG(i), 0);
+               hpi_read_word(dev, SIEMSG_REG(i));
+       }
+}
+
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
+{
+       hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+                    SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
+{
+       hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+                      SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+/* Transactions */
+
+static inline u16 ll_recv_msg(struct c67x00_device *dev)
+{
+       u16 res;
+
+       res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
+       WARN_ON(!res);
+
+       return (res == 0) ? -EIO : 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* General functions */
+
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
+{
+       u16 val;
+
+       val = hpi_read_word(dev, SIEMSG_REG(sie_num));
+       /* clear register to allow next message */
+       hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
+
+       return val;
+}
+
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
+{
+       return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
+}
+
+/**
+ * c67x00_ll_usb_clear_status - clear the USB status bits
+ */
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
+{
+       hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
+}
+
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
+{
+       return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
+                               struct c67x00_lcp_int_data *data)
+{
+       int i, rc;
+
+       mutex_lock(&dev->hpi.lcp.mutex);
+       hpi_write_word(dev, COMM_INT_NUM, nr);
+       for (i = 0; i < COMM_REGS; i++)
+               hpi_write_word(dev, COMM_R(i), data->regs[i]);
+       hpi_send_mbox(dev, COMM_EXEC_INT);
+       rc = ll_recv_msg(dev);
+       mutex_unlock(&dev->hpi.lcp.mutex);
+
+       return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Host specific functions */
+
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
+{
+       mutex_lock(&dev->hpi.lcp.mutex);
+       hpi_write_word(dev, HUSB_pEOT, value);
+       mutex_unlock(&dev->hpi.lcp.mutex);
+}
+
+static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
+{
+       struct c67x00_device *dev = sie->dev;
+       struct c67x00_lcp_int_data data;
+       int rc;
+
+       rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
+       BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
+{
+       struct c67x00_device *dev = sie->dev;
+       struct c67x00_lcp_int_data data;
+       int rc;
+
+       data.regs[0] = 50;      /* Reset USB port for 50ms */
+       data.regs[1] = port | (sie->sie_num << 1);
+       rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data);
+       BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr)
+{
+       hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr);
+}
+
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
+{
+       return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
+}
+
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
+{
+       return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
+}
+
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
+{
+       /* Set port into host mode */
+       hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
+       c67x00_ll_husb_sie_init(sie);
+       /* Clear interrupts */
+       c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
+       /* Check */
+       if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
+               dev_warn(sie_dev(sie),
+                        "SIE %d not set to host mode\n", sie->sie_num);
+}
+
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
+{
+       /* Clear connect change */
+       c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
+
+       /* Enable interrupts */
+       hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+                    SOFEOP_TO_CPU_EN(sie->sie_num));
+       hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num),
+                    SOF_EOP_IRQ_EN | DONE_IRQ_EN);
+
+       /* Enable pull down transistors */
+       hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port));
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
+{
+       if ((int_status & MBX_OUT_FLG) == 0)
+               return;
+
+       dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
+       complete(&dev->hpi.lcp.msg_received);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int c67x00_ll_reset(struct c67x00_device *dev)
+{
+       int rc;
+
+       mutex_lock(&dev->hpi.lcp.mutex);
+       hpi_send_mbox(dev, COMM_RESET);
+       rc = ll_recv_msg(dev);
+       mutex_unlock(&dev->hpi.lcp.mutex);
+
+       return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_ll_write_mem_le16 - write into c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+                             void *data, int len)
+{
+       u8 *buf = data;
+
+       /* Sanity check */
+       if (addr + len > 0xffff) {
+               dev_err(&dev->pdev->dev,
+                       "Trying to write beyond writable region!\n");
+               return;
+       }
+
+       if (addr & 0x01) {
+               /* unaligned access */
+               u16 tmp;
+               tmp = hpi_read_word(dev, addr - 1);
+               tmp = (tmp & 0x00ff) | (*buf++ << 8);
+               hpi_write_word(dev, addr - 1, tmp);
+               addr++;
+               len--;
+       }
+
+       hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
+       buf += len & ~0x01;
+       addr += len & ~0x01;
+       len &= 0x01;
+
+       if (len) {
+               u16 tmp;
+               tmp = hpi_read_word(dev, addr);
+               tmp = (tmp & 0xff00) | *buf;
+               hpi_write_word(dev, addr, tmp);
+       }
+}
+
+/**
+ * c67x00_ll_read_mem_le16 - read from c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+                            void *data, int len)
+{
+       u8 *buf = data;
+
+       if (addr & 0x01) {
+               /* unaligned access */
+               u16 tmp;
+               tmp = hpi_read_word(dev, addr - 1);
+               *buf++ = (tmp >> 8) & 0x00ff;
+               addr++;
+               len--;
+       }
+
+       hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
+       buf += len & ~0x01;
+       addr += len & ~0x01;
+       len &= 0x01;
+
+       if (len) {
+               u16 tmp;
+               tmp = hpi_read_word(dev, addr);
+               *buf = tmp & 0x00ff;
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_init(struct c67x00_device *dev)
+{
+       mutex_init(&dev->hpi.lcp.mutex);
+       init_completion(&dev->hpi.lcp.msg_received);
+}
+
+void c67x00_ll_release(struct c67x00_device *dev)
+{
+}
diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c
new file mode 100644 (file)
index 0000000..85dfe29
--- /dev/null
@@ -0,0 +1,1170 @@
+/*
+ * c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#include <linux/kthread.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/*
+ * These are the stages for a control urb, they are kept
+ * in both urb->interval and td->privdata.
+ */
+#define SETUP_STAGE            0
+#define DATA_STAGE             1
+#define STATUS_STAGE           2
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * struct c67x00_ep_data: Host endpoint data structure
+ */
+struct c67x00_ep_data {
+       struct list_head queue;
+       struct list_head node;
+       struct usb_host_endpoint *hep;
+       struct usb_device *dev;
+       u16 next_frame;         /* For int/isoc transactions */
+};
+
+/**
+ * struct c67x00_td
+ *
+ * Hardware parts are little endiannes, SW in CPU endianess.
+ */
+struct c67x00_td {
+       /* HW specific part */
+       __le16 ly_base_addr;    /* Bytes 0-1 */
+       __le16 port_length;     /* Bytes 2-3 */
+       u8 pid_ep;              /* Byte 4 */
+       u8 dev_addr;            /* Byte 5 */
+       u8 ctrl_reg;            /* Byte 6 */
+       u8 status;              /* Byte 7 */
+       u8 retry_cnt;           /* Byte 8 */
+#define TT_OFFSET              2
+#define TT_CONTROL             0
+#define TT_ISOCHRONOUS         1
+#define TT_BULK                        2
+#define TT_INTERRUPT           3
+       u8 residue;             /* Byte 9 */
+       __le16 next_td_addr;    /* Bytes 10-11 */
+       /* SW part */
+       struct list_head td_list;
+       u16 td_addr;
+       void *data;
+       struct urb *urb;
+       unsigned long privdata;
+
+       /* These are needed for handling the toggle bits:
+        * an urb can be dequeued while a td is in progress
+        * after checking the td, the toggle bit might need to
+        * be fixed */
+       struct c67x00_ep_data *ep_data;
+       unsigned int pipe;
+};
+
+struct c67x00_urb_priv {
+       struct list_head hep_node;
+       struct urb *urb;
+       int port;
+       int cnt;                /* packet number for isoc */
+       int status;
+       struct c67x00_ep_data *ep_data;
+};
+
+#define td_udev(td)    ((td)->ep_data->dev)
+
+#define CY_TD_SIZE             12
+
+#define TD_PIDEP_OFFSET                0x04
+#define TD_PIDEPMASK_PID       0xF0
+#define TD_PIDEPMASK_EP                0x0F
+#define TD_PORTLENMASK_DL      0x02FF
+#define TD_PORTLENMASK_PN      0xC000
+
+#define TD_STATUS_OFFSET       0x07
+#define TD_STATUSMASK_ACK      0x01
+#define TD_STATUSMASK_ERR      0x02
+#define TD_STATUSMASK_TMOUT    0x04
+#define TD_STATUSMASK_SEQ      0x08
+#define TD_STATUSMASK_SETUP    0x10
+#define TD_STATUSMASK_OVF      0x20
+#define TD_STATUSMASK_NAK      0x40
+#define TD_STATUSMASK_STALL    0x80
+
+#define TD_ERROR_MASK          (TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \
+                                TD_STATUSMASK_STALL)
+
+#define TD_RETRYCNT_OFFSET     0x08
+#define TD_RETRYCNTMASK_ACT_FLG        0x10
+#define TD_RETRYCNTMASK_TX_TYPE        0x0C
+#define TD_RETRYCNTMASK_RTY_CNT        0x03
+
+#define TD_RESIDUE_OVERFLOW    0x80
+
+#define TD_PID_IN              0x90
+
+/* Residue: signed 8bits, neg -> OVERFLOW, pos -> UNDERFLOW */
+#define td_residue(td)         ((__s8)(td->residue))
+#define td_ly_base_addr(td)    (__le16_to_cpu((td)->ly_base_addr))
+#define td_port_length(td)     (__le16_to_cpu((td)->port_length))
+#define td_next_td_addr(td)    (__le16_to_cpu((td)->next_td_addr))
+
+#define td_active(td)          ((td)->retry_cnt & TD_RETRYCNTMASK_ACT_FLG)
+#define td_length(td)          (td_port_length(td) & TD_PORTLENMASK_DL)
+
+#define td_sequence_ok(td)     (!td->status || \
+                                (!(td->status & TD_STATUSMASK_SEQ) ==  \
+                                 !(td->ctrl_reg & SEQ_SEL)))
+
+#define td_acked(td)           (!td->status || \
+                                (td->status & TD_STATUSMASK_ACK))
+#define td_actual_bytes(td)    (td_length(td) - td_residue(td))
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef DEBUG
+
+/**
+ * dbg_td - Dump the contents of the TD
+ */
+static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)
+{
+       struct device *dev = c67x00_hcd_dev(c67x00);
+
+       dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr);
+       dev_dbg(dev, "urb:      0x%p\n", td->urb);
+       dev_dbg(dev, "endpoint:   %4d\n", usb_pipeendpoint(td->pipe));
+       dev_dbg(dev, "pipeout:    %4d\n", usb_pipeout(td->pipe));
+       dev_dbg(dev, "ly_base_addr: 0x%04x\n", td_ly_base_addr(td));
+       dev_dbg(dev, "port_length:  0x%04x\n", td_port_length(td));
+       dev_dbg(dev, "pid_ep:         0x%02x\n", td->pid_ep);
+       dev_dbg(dev, "dev_addr:       0x%02x\n", td->dev_addr);
+       dev_dbg(dev, "ctrl_reg:       0x%02x\n", td->ctrl_reg);
+       dev_dbg(dev, "status:         0x%02x\n", td->status);
+       dev_dbg(dev, "retry_cnt:      0x%02x\n", td->retry_cnt);
+       dev_dbg(dev, "residue:        0x%02x\n", td->residue);
+       dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td));
+       dev_dbg(dev, "data:");
+       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
+                      td->data, td_length(td), 1);
+}
+#else                          /* DEBUG */
+
+static inline void
+dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { }
+
+#endif                         /* DEBUG */
+
+/* -------------------------------------------------------------------------- */
+/* Helper functions */
+
+static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00)
+{
+       return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_add
+ * Software wraparound for framenumbers.
+ */
+static inline u16 frame_add(u16 a, u16 b)
+{
+       return (a + b) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_after - is frame a after frame b
+ */
+static inline int frame_after(u16 a, u16 b)
+{
+       return ((HOST_FRAME_MASK + a - b) & HOST_FRAME_MASK) <
+           (HOST_FRAME_MASK / 2);
+}
+
+/**
+ * frame_after_eq - is frame a after or equal to frame b
+ */
+static inline int frame_after_eq(u16 a, u16 b)
+{
+       return ((HOST_FRAME_MASK + 1 + a - b) & HOST_FRAME_MASK) <
+           (HOST_FRAME_MASK / 2);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_release_urb - remove link from all tds to this urb
+ * Disconnects the urb from it's tds, so that it can be given back.
+ * pre: urb->hcpriv != NULL
+ */
+static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+       struct c67x00_td *td;
+       struct c67x00_urb_priv *urbp;
+
+       BUG_ON(!urb);
+
+       c67x00->urb_count--;
+
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               c67x00->urb_iso_count--;
+               if (c67x00->urb_iso_count == 0)
+                       c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+       }
+
+       /* TODO this might be not so efficient when we've got many urbs!
+        * Alternatives:
+        *   * only clear when needed
+        *   * keep a list of tds with each urbp
+        */
+       list_for_each_entry(td, &c67x00->td_list, td_list)
+               if (urb == td->urb)
+                       td->urb = NULL;
+
+       urbp = urb->hcpriv;
+       urb->hcpriv = NULL;
+       list_del(&urbp->hep_node);
+       kfree(urbp);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct c67x00_ep_data *
+c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+       struct usb_host_endpoint *hep = urb->ep;
+       struct c67x00_ep_data *ep_data;
+       int type;
+
+       c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+
+       /* Check if endpoint already has a c67x00_ep_data struct allocated */
+       if (hep->hcpriv) {
+               ep_data = hep->hcpriv;
+               if (frame_after(c67x00->current_frame, ep_data->next_frame))
+                       ep_data->next_frame =
+                           frame_add(c67x00->current_frame, 1);
+               return hep->hcpriv;
+       }
+
+       /* Allocate and initialize a new c67x00 endpoint data structure */
+       ep_data = kzalloc(sizeof(*ep_data), GFP_ATOMIC);
+       if (!ep_data)
+               return NULL;
+
+       INIT_LIST_HEAD(&ep_data->queue);
+       INIT_LIST_HEAD(&ep_data->node);
+       ep_data->hep = hep;
+
+       /* hold a reference to udev as long as this endpoint lives,
+        * this is needed to possibly fix the data toggle */
+       ep_data->dev = usb_get_dev(urb->dev);
+       hep->hcpriv = ep_data;
+
+       /* For ISOC and INT endpoints, start ASAP: */
+       ep_data->next_frame = frame_add(c67x00->current_frame, 1);
+
+       /* Add the endpoint data to one of the pipe lists; must be added
+          in order of endpoint address */
+       type = usb_pipetype(urb->pipe);
+       if (list_empty(&ep_data->node)) {
+               list_add(&ep_data->node, &c67x00->list[type]);
+       } else {
+               struct c67x00_ep_data *prev;
+
+               list_for_each_entry(prev, &c67x00->list[type], node) {
+                       if (prev->hep->desc.bEndpointAddress >
+                           hep->desc.bEndpointAddress) {
+                               list_add(&ep_data->node, prev->node.prev);
+                               break;
+                       }
+               }
+       }
+
+       return ep_data;
+}
+
+static int c67x00_ep_data_free(struct usb_host_endpoint *hep)
+{
+       struct c67x00_ep_data *ep_data = hep->hcpriv;
+
+       if (!ep_data)
+               return 0;
+
+       if (!list_empty(&ep_data->queue))
+               return -EBUSY;
+
+       usb_put_dev(ep_data->dev);
+       list_del(&ep_data->queue);
+       list_del(&ep_data->node);
+
+       kfree(ep_data);
+       hep->hcpriv = NULL;
+
+       return 0;
+}
+
+void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+       struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+       unsigned long flags;
+
+       if (!list_empty(&ep->urb_list))
+               dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n");
+
+       spin_lock_irqsave(&c67x00->lock, flags);
+
+       /* loop waiting for all transfers in the endpoint queue to complete */
+       while (c67x00_ep_data_free(ep)) {
+               /* Drop the lock so we can sleep waiting for the hardware */
+               spin_unlock_irqrestore(&c67x00->lock, flags);
+
+               /* it could happen that we reinitialize this completion, while
+                * somebody was waiting for that completion.  The timeout and
+                * while loop handle such cases, but this might be improved */
+               INIT_COMPLETION(c67x00->endpoint_disable);
+               c67x00_sched_kick(c67x00);
+               wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ);
+
+               spin_lock_irqsave(&c67x00->lock, flags);
+       }
+
+       spin_unlock_irqrestore(&c67x00->lock, flags);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int get_root_port(struct usb_device *dev)
+{
+       while (dev->parent->parent)
+               dev = dev->parent;
+       return dev->portnum;
+}
+
+int c67x00_urb_enqueue(struct usb_hcd *hcd,
+                      struct urb *urb, gfp_t mem_flags)
+{
+       int ret;
+       unsigned long flags;
+       struct c67x00_urb_priv *urbp;
+       struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+       int port = get_root_port(urb->dev)-1;
+
+       spin_lock_irqsave(&c67x00->lock, flags);
+
+       /* Make sure host controller is running */
+       if (!HC_IS_RUNNING(hcd->state)) {
+               ret = -ENODEV;
+               goto err_not_linked;
+       }
+
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret)
+               goto err_not_linked;
+
+       /* Allocate and initialize urb private data */
+       urbp = kzalloc(sizeof(*urbp), mem_flags);
+       if (!urbp) {
+               ret = -ENOMEM;
+               goto err_urbp;
+       }
+
+       INIT_LIST_HEAD(&urbp->hep_node);
+       urbp->urb = urb;
+       urbp->port = port;
+
+       urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb);
+
+       if (!urbp->ep_data) {
+               ret = -ENOMEM;
+               goto err_epdata;
+       }
+
+       /* TODO claim bandwidth with usb_claim_bandwidth?
+        * also release it somewhere! */
+
+       urb->hcpriv = urbp;
+
+       urb->actual_length = 0; /* Nothing received/transmitted yet */
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_CONTROL:
+               urb->interval = SETUP_STAGE;
+               break;
+       case PIPE_INTERRUPT:
+               break;
+       case PIPE_BULK:
+               break;
+       case PIPE_ISOCHRONOUS:
+               if (c67x00->urb_iso_count == 0)
+                       c67x00->max_frame_bw = MAX_FRAME_BW_ISO;
+               c67x00->urb_iso_count++;
+               /* Assume always URB_ISO_ASAP, FIXME */
+               if (list_empty(&urbp->ep_data->queue))
+                       urb->start_frame = urbp->ep_data->next_frame;
+               else {
+                       /* Go right after the last one */
+                       struct urb *last_urb;
+
+                       last_urb = list_entry(urbp->ep_data->queue.prev,
+                                             struct c67x00_urb_priv,
+                                             hep_node)->urb;
+                       urb->start_frame =
+                           frame_add(last_urb->start_frame,
+                                     last_urb->number_of_packets *
+                                     last_urb->interval);
+               }
+               urbp->cnt = 0;
+               break;
+       }
+
+       /* Add the URB to the endpoint queue */
+       list_add_tail(&urbp->hep_node, &urbp->ep_data->queue);
+
+       /* If this is the only URB, kick start the controller */
+       if (!c67x00->urb_count++)
+               c67x00_ll_hpi_enable_sofeop(c67x00->sie);
+
+       c67x00_sched_kick(c67x00);
+       spin_unlock_irqrestore(&c67x00->lock, flags);
+
+       return 0;
+
+err_epdata:
+       kfree(urbp);
+err_urbp:
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
+err_not_linked:
+       spin_unlock_irqrestore(&c67x00->lock, flags);
+
+       return ret;
+}
+
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+       struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&c67x00->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
+       c67x00_release_urb(c67x00, urb);
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+       spin_unlock(&c67x00->lock);
+       usb_hcd_giveback_urb(hcd, urb, status);
+       spin_lock(&c67x00->lock);
+
+       spin_unlock_irqrestore(&c67x00->lock, flags);
+
+       return 0;
+
+ done:
+       spin_unlock_irqrestore(&c67x00->lock, flags);
+       return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * pre: c67x00 locked, urb unlocked
+ */
+static void
+c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
+{
+       struct c67x00_urb_priv *urbp;
+
+       if (!urb)
+               return;
+
+       urbp = urb->hcpriv;
+       urbp->status = status;
+
+       list_del_init(&urbp->hep_node);
+
+       c67x00_release_urb(c67x00, urb);
+       usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb);
+       spin_unlock(&c67x00->lock);
+       usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, urbp->status);
+       spin_lock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
+                                int len, int periodic)
+{
+       struct c67x00_urb_priv *urbp = urb->hcpriv;
+       int bit_time;
+
+       /* According to the C67x00 BIOS user manual, page 3-18,19, the
+        * following calculations provide the full speed bit times for
+        * a transaction.
+        *
+        * FS(in)       = 112.5 +  9.36*BC + HOST_DELAY
+        * FS(in,iso)   =  90.5 +  9.36*BC + HOST_DELAY
+        * FS(out)      = 112.5 +  9.36*BC + HOST_DELAY
+        * FS(out,iso)  =  78.4 +  9.36*BC + HOST_DELAY
+        * LS(in)       = 802.4 + 75.78*BC + HOST_DELAY
+        * LS(out)      = 802.6 + 74.67*BC + HOST_DELAY
+        *
+        * HOST_DELAY == 106 for the c67200 and c67300.
+        */
+
+       /* make calculations in 1/100 bit times to maintain resolution */
+       if (urbp->ep_data->dev->speed == USB_SPEED_LOW) {
+               /* Low speed pipe */
+               if (usb_pipein(urb->pipe))
+                       bit_time = 80240 + 7578*len;
+               else
+                       bit_time = 80260 + 7467*len;
+       } else {
+               /* FS pipes */
+               if (usb_pipeisoc(urb->pipe))
+                       bit_time = usb_pipein(urb->pipe) ? 9050 : 7840;
+               else
+                       bit_time = 11250;
+               bit_time += 936*len;
+       }
+
+       /* Scale back down to integer bit times.  Use a host delay of 106.
+        * (this is the only place it is used) */
+       bit_time = ((bit_time+50) / 100) + 106;
+
+       if (unlikely(bit_time + c67x00->bandwidth_allocated >=
+                    c67x00->max_frame_bw))
+               return -EMSGSIZE;
+
+       if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >=
+                    c67x00->td_base_addr + SIE_TD_SIZE))
+               return -EMSGSIZE;
+
+       if (unlikely(c67x00->next_buf_addr + len >=
+                    c67x00->buf_base_addr + SIE_TD_BUF_SIZE))
+               return -EMSGSIZE;
+
+       if (periodic) {
+               if (unlikely(bit_time + c67x00->periodic_bw_allocated >=
+                            MAX_PERIODIC_BW(c67x00->max_frame_bw)))
+                       return -EMSGSIZE;
+               c67x00->periodic_bw_allocated += bit_time;
+       }
+
+       c67x00->bandwidth_allocated += bit_time;
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * td_addr and buf_addr must be word aligned
+ */
+static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb,
+                           void *data, int len, int pid, int toggle,
+                           unsigned long privdata)
+{
+       struct c67x00_td *td;
+       struct c67x00_urb_priv *urbp = urb->hcpriv;
+       const __u8 active_flag = 1, retry_cnt = 1;
+       __u8 cmd = 0;
+       int tt = 0;
+
+       if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe)
+                                 || usb_pipeint(urb->pipe)))
+               return -EMSGSIZE;       /* Not really an error, but expected */
+
+       td = kzalloc(sizeof(*td), GFP_ATOMIC);
+       if (!td)
+               return -ENOMEM;
+
+       td->pipe = urb->pipe;
+       td->ep_data = urbp->ep_data;
+
+       if ((td_udev(td)->speed == USB_SPEED_LOW) &&
+           !(c67x00->low_speed_ports & (1 << urbp->port)))
+               cmd |= PREAMBLE_EN;
+
+       switch (usb_pipetype(td->pipe)) {
+       case PIPE_ISOCHRONOUS:
+               tt = TT_ISOCHRONOUS;
+               cmd |= ISO_EN;
+               break;
+       case PIPE_CONTROL:
+               tt = TT_CONTROL;
+               break;
+       case PIPE_BULK:
+               tt = TT_BULK;
+               break;
+       case PIPE_INTERRUPT:
+               tt = TT_INTERRUPT;
+               break;
+       }
+
+       if (toggle)
+               cmd |= SEQ_SEL;
+
+       cmd |= ARM_EN;
+
+       /* SW part */
+       td->td_addr = c67x00->next_td_addr;
+       c67x00->next_td_addr = c67x00->next_td_addr + CY_TD_SIZE;
+
+       /* HW part */
+       td->ly_base_addr = __cpu_to_le16(c67x00->next_buf_addr);
+       td->port_length = __cpu_to_le16((c67x00->sie->sie_num << 15) |
+                                       (urbp->port << 14) | (len & 0x3FF));
+       td->pid_ep = ((pid & 0xF) << TD_PIDEP_OFFSET) |
+           (usb_pipeendpoint(td->pipe) & 0xF);
+       td->dev_addr = usb_pipedevice(td->pipe) & 0x7F;
+       td->ctrl_reg = cmd;
+       td->status = 0;
+       td->retry_cnt = (tt << TT_OFFSET) | (active_flag << 4) | retry_cnt;
+       td->residue = 0;
+       td->next_td_addr = __cpu_to_le16(c67x00->next_td_addr);
+
+       /* SW part */
+       td->data = data;
+       td->urb = urb;
+       td->privdata = privdata;
+
+       c67x00->next_buf_addr += (len + 1) & ~0x01;     /* properly align */
+
+       list_add_tail(&td->td_list, &c67x00->td_list);
+       return 0;
+}
+
+static inline void c67x00_release_td(struct c67x00_td *td)
+{
+       list_del_init(&td->td_list);
+       kfree(td);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+       int remaining;
+       int toggle;
+       int pid;
+       int ret = 0;
+       int maxps;
+       int need_empty;
+
+       toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                              usb_pipeout(urb->pipe));
+       remaining = urb->transfer_buffer_length - urb->actual_length;
+
+       maxps = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+       need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+           usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+       while (remaining || need_empty) {
+               int len;
+               char *td_buf;
+
+               len = (remaining > maxps) ? maxps : remaining;
+               if (!len)
+                       need_empty = 0;
+
+               pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+               td_buf = urb->transfer_buffer + urb->transfer_buffer_length -
+                   remaining;
+               ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle,
+                                      DATA_STAGE);
+               if (ret)
+                       return ret;     /* td wasn't created */
+
+               toggle ^= 1;
+               remaining -= len;
+               if (usb_pipecontrol(urb->pipe))
+                       break;
+       }
+
+       return 0;
+}
+
+/**
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+       int ret;
+       int pid;
+
+       switch (urb->interval) {
+       default:
+       case SETUP_STAGE:
+               ret = c67x00_create_td(c67x00, urb, urb->setup_packet,
+                                      8, USB_PID_SETUP, 0, SETUP_STAGE);
+               if (ret)
+                       return ret;
+               urb->interval = SETUP_STAGE;
+               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                             usb_pipeout(urb->pipe), 1);
+               break;
+       case DATA_STAGE:
+               if (urb->transfer_buffer_length) {
+                       ret = c67x00_add_data_urb(c67x00, urb);
+                       if (ret)
+                               return ret;
+                       break;
+               }               /* else fallthrough */
+       case STATUS_STAGE:
+               pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+               ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1,
+                                      STATUS_STAGE);
+               if (ret)
+                       return ret;
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+       struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+       if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+               urbp->ep_data->next_frame =
+                   frame_add(urbp->ep_data->next_frame, urb->interval);
+               return c67x00_add_data_urb(c67x00, urb);
+       }
+       return 0;
+}
+
+static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+       struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+       if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+               char *td_buf;
+               int len, pid, ret;
+
+               BUG_ON(urbp->cnt >= urb->number_of_packets);
+
+               td_buf = urb->transfer_buffer +
+                   urb->iso_frame_desc[urbp->cnt].offset;
+               len = urb->iso_frame_desc[urbp->cnt].length;
+               pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+
+               ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0,
+                                      urbp->cnt);
+               if (ret) {
+                       printk(KERN_DEBUG "create failed: %d\n", ret);
+                       urb->iso_frame_desc[urbp->cnt].actual_length = 0;
+                       urb->iso_frame_desc[urbp->cnt].status = ret;
+                       if (urbp->cnt + 1 == urb->number_of_packets)
+                               c67x00_giveback_urb(c67x00, urb, 0);
+               }
+
+               urbp->ep_data->next_frame =
+                   frame_add(urbp->ep_data->next_frame, urb->interval);
+               urbp->cnt++;
+       }
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type,
+                                 int (*add)(struct c67x00_hcd *, struct urb *))
+{
+       struct c67x00_ep_data *ep_data;
+       struct urb *urb;
+
+       /* traverse every endpoint on the list */
+       list_for_each_entry(ep_data, &c67x00->list[type], node) {
+               if (!list_empty(&ep_data->queue)) {
+                       /* and add the first urb */
+                       /* isochronous transfer rely on this */
+                       urb = list_entry(ep_data->queue.next,
+                                        struct c67x00_urb_priv,
+                                        hep_node)->urb;
+                       add(c67x00, urb);
+               }
+       }
+}
+
+static void c67x00_fill_frame(struct c67x00_hcd *c67x00)
+{
+       struct c67x00_td *td, *ttd;
+
+       /* Check if we can proceed */
+       if (!list_empty(&c67x00->td_list)) {
+               dev_warn(c67x00_hcd_dev(c67x00),
+                        "TD list not empty! This should not happen!\n");
+               list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) {
+                       dbg_td(c67x00, td, "Unprocessed td");
+                       c67x00_release_td(td);
+               }
+       }
+
+       /* Reinitialize variables */
+       c67x00->bandwidth_allocated = 0;
+       c67x00->periodic_bw_allocated = 0;
+
+       c67x00->next_td_addr = c67x00->td_base_addr;
+       c67x00->next_buf_addr = c67x00->buf_base_addr;
+
+       /* Fill the list */
+       c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb);
+       c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb);
+       c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb);
+       c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Get TD from C67X00
+ */
+static inline void
+c67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+       c67x00_ll_read_mem_le16(c67x00->sie->dev,
+                               td->td_addr, td, CY_TD_SIZE);
+
+       if (usb_pipein(td->pipe) && td_actual_bytes(td))
+               c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+                                       td->data, td_actual_bytes(td));
+}
+
+static int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+       if (td->status & TD_STATUSMASK_ERR) {
+               dbg_td(c67x00, td, "ERROR_FLAG");
+               return -EILSEQ;
+       }
+       if (td->status & TD_STATUSMASK_STALL) {
+               /* dbg_td(c67x00, td, "STALL"); */
+               return -EPIPE;
+       }
+       if (td->status & TD_STATUSMASK_TMOUT) {
+               dbg_td(c67x00, td, "TIMEOUT");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static inline int c67x00_end_of_data(struct c67x00_td *td)
+{
+       int maxps, need_empty, remaining;
+       struct urb *urb = td->urb;
+       int act_bytes;
+
+       act_bytes = td_actual_bytes(td);
+
+       if (unlikely(!act_bytes))
+               return 1;       /* This was an empty packet */
+
+       maxps = usb_maxpacket(td_udev(td), td->pipe, usb_pipeout(td->pipe));
+
+       if (unlikely(act_bytes < maxps))
+               return 1;       /* Smaller then full packet */
+
+       remaining = urb->transfer_buffer_length - urb->actual_length;
+       need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+           usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+       if (unlikely(!remaining && !need_empty))
+               return 1;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Remove all td's from the list which come
+ * after last_td and are meant for the same pipe.
+ * This is used when a short packet has occured */
+static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00,
+                                    struct c67x00_td *last_td)
+{
+       struct c67x00_td *td, *tmp;
+       td = last_td;
+       tmp = last_td;
+       while (td->td_list.next != &c67x00->td_list) {
+               td = list_entry(td->td_list.next, struct c67x00_td, td_list);
+               if (td->pipe == last_td->pipe) {
+                       c67x00_release_td(td);
+                       td = tmp;
+               }
+               tmp = td;
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00,
+                                       struct c67x00_td *td)
+{
+       struct urb *urb = td->urb;
+
+       if (!urb)
+               return;
+
+       urb->actual_length += td_actual_bytes(td);
+
+       switch (usb_pipetype(td->pipe)) {
+               /* isochronous tds are handled separately */
+       case PIPE_CONTROL:
+               switch (td->privdata) {
+               case SETUP_STAGE:
+                       urb->interval =
+                           urb->transfer_buffer_length ?
+                           DATA_STAGE : STATUS_STAGE;
+                       /* Don't count setup_packet with normal data: */
+                       urb->actual_length = 0;
+                       break;
+
+               case DATA_STAGE:
+                       if (c67x00_end_of_data(td)) {
+                               urb->interval = STATUS_STAGE;
+                               c67x00_clear_pipe(c67x00, td);
+                       }
+                       break;
+
+               case STATUS_STAGE:
+                       urb->interval = 0;
+                       c67x00_giveback_urb(c67x00, urb, 0);
+                       break;
+               }
+               break;
+
+       case PIPE_INTERRUPT:
+       case PIPE_BULK:
+               if (unlikely(c67x00_end_of_data(td))) {
+                       c67x00_clear_pipe(c67x00, td);
+                       c67x00_giveback_urb(c67x00, urb, 0);
+               }
+               break;
+       }
+}
+
+static void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+       struct urb *urb = td->urb;
+       struct c67x00_urb_priv *urbp;
+       int cnt;
+
+       if (!urb)
+               return;
+
+       urbp = urb->hcpriv;
+       cnt = td->privdata;
+
+       if (td->status & TD_ERROR_MASK)
+               urb->error_count++;
+
+       urb->iso_frame_desc[cnt].actual_length = td_actual_bytes(td);
+       urb->iso_frame_desc[cnt].status = c67x00_td_to_error(c67x00, td);
+       if (cnt + 1 == urb->number_of_packets)  /* Last packet */
+               c67x00_giveback_urb(c67x00, urb, 0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_check_td_list - handle tds which have been processed by the c67x00
+ * pre: current_td == 0
+ */
+static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
+{
+       struct c67x00_td *td, *tmp;
+       struct urb *urb;
+       int ack_ok;
+       int clear_endpoint;
+
+       list_for_each_entry_safe(td, tmp, &c67x00->td_list, td_list) {
+               /* get the TD */
+               c67x00_parse_td(c67x00, td);
+               urb = td->urb;  /* urb can be NULL! */
+               ack_ok = 0;
+               clear_endpoint = 1;
+
+               /* Handle isochronous transfers separately */
+               if (usb_pipeisoc(td->pipe)) {
+                       clear_endpoint = 0;
+                       c67x00_handle_isoc(c67x00, td);
+                       goto cont;
+               }
+
+               /* When an error occurs, all td's for that pipe go into an
+                * inactive state. This state matches successful transfers so
+                * we must make sure not to service them. */
+               if (td->status & TD_ERROR_MASK) {
+                       c67x00_giveback_urb(c67x00, urb,
+                                           c67x00_td_to_error(c67x00, td));
+                       goto cont;
+               }
+
+               if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) ||
+                   !td_acked(td))
+                       goto cont;
+
+               /* Sequence ok and acked, don't need to fix toggle */
+               ack_ok = 1;
+
+               if (unlikely(td->status & TD_STATUSMASK_OVF)) {
+                       if (td_residue(td) & TD_RESIDUE_OVERFLOW) {
+                               /* Overflow */
+                               c67x00_giveback_urb(c67x00, urb, -EOVERFLOW);
+                               goto cont;
+                       }
+               }
+
+               clear_endpoint = 0;
+               c67x00_handle_successful_td(c67x00, td);
+
+cont:
+               if (clear_endpoint)
+                       c67x00_clear_pipe(c67x00, td);
+               if (ack_ok)
+                       usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe),
+                                     usb_pipeout(td->pipe),
+                                     !(td->ctrl_reg & SEQ_SEL));
+               /* next in list could have been removed, due to clear_pipe! */
+               tmp = list_entry(td->td_list.next, typeof(*td), td_list);
+               c67x00_release_td(td);
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00)
+{
+       /* If all tds are processed, we can check the previous frame (if
+        * there was any) and start our next frame.
+        */
+       return !c67x00_ll_husb_get_current_td(c67x00->sie);
+}
+
+/**
+ * Send td to C67X00
+ */
+static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+       int len = td_length(td);
+
+       if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN))
+               c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+                                        td->data, len);
+
+       c67x00_ll_write_mem_le16(c67x00->sie->dev,
+                                td->td_addr, td, CY_TD_SIZE);
+}
+
+static void c67x00_send_frame(struct c67x00_hcd *c67x00)
+{
+       struct c67x00_td *td;
+
+       if (list_empty(&c67x00->td_list))
+               dev_warn(c67x00_hcd_dev(c67x00),
+                        "%s: td list should not be empty here!\n",
+                        __func__);
+
+       list_for_each_entry(td, &c67x00->td_list, td_list) {
+               if (td->td_list.next == &c67x00->td_list)
+                       td->next_td_addr = 0;   /* Last td in list */
+
+               c67x00_send_td(c67x00, td);
+       }
+
+       c67x00_ll_husb_set_current_td(c67x00->sie, c67x00->td_base_addr);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_do_work - Schedulers state machine
+ */
+static void c67x00_do_work(struct c67x00_hcd *c67x00)
+{
+       spin_lock(&c67x00->lock);
+       /* Make sure all tds are processed */
+       if (!c67x00_all_tds_processed(c67x00))
+               goto out;
+
+       c67x00_check_td_list(c67x00);
+
+       /* no td's are being processed (current == 0)
+        * and all have been "checked" */
+       complete(&c67x00->endpoint_disable);
+
+       if (!list_empty(&c67x00->td_list))
+               goto out;
+
+       c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+       if (c67x00->current_frame == c67x00->last_frame)
+               goto out;       /* Don't send tds in same frame */
+       c67x00->last_frame = c67x00->current_frame;
+
+       /* If no urbs are scheduled, our work is done */
+       if (!c67x00->urb_count) {
+               c67x00_ll_hpi_disable_sofeop(c67x00->sie);
+               goto out;
+       }
+
+       c67x00_fill_frame(c67x00);
+       if (!list_empty(&c67x00->td_list))
+               /* TD's have been added to the frame */
+               c67x00_send_frame(c67x00);
+
+ out:
+       spin_unlock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_sched_tasklet(unsigned long __c67x00)
+{
+       struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00;
+       c67x00_do_work(c67x00);
+}
+
+void c67x00_sched_kick(struct c67x00_hcd *c67x00)
+{
+       tasklet_hi_schedule(&c67x00->tasklet);
+}
+
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00)
+{
+       tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet,
+                    (unsigned long)c67x00);
+       return 0;
+}
+
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00)
+{
+       tasklet_kill(&c67x00->tasklet);
+}
diff --git a/drivers/usb/c67x00/c67x00.h b/drivers/usb/c67x00/c67x00.h
new file mode 100644 (file)
index 0000000..a26e9de
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * c67x00.h: Cypress C67X00 USB register and field definitions
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#ifndef _USB_C67X00_H
+#define _USB_C67X00_H
+
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+/* ---------------------------------------------------------------------
+ * Cypress C67x00 register definitions
+ */
+
+/* Hardware Revision Register */
+#define HW_REV_REG             0xC004
+
+/* General USB registers */
+/* ===================== */
+
+/* USB Control Register */
+#define USB_CTL_REG(x)         ((x) ? 0xC0AA : 0xC08A)
+
+#define LOW_SPEED_PORT(x)      ((x) ? 0x0800 : 0x0400)
+#define HOST_MODE              0x0200
+#define PORT_RES_EN(x)         ((x) ? 0x0100 : 0x0080)
+#define SOF_EOP_EN(x)          ((x) ? 0x0002 : 0x0001)
+
+/* USB status register - Notice it has different content in hcd/udc mode */
+#define USB_STAT_REG(x)                ((x) ? 0xC0B0 : 0xC090)
+
+#define EP0_IRQ_FLG            0x0001
+#define EP1_IRQ_FLG            0x0002
+#define EP2_IRQ_FLG            0x0004
+#define EP3_IRQ_FLG            0x0008
+#define EP4_IRQ_FLG            0x0010
+#define EP5_IRQ_FLG            0x0020
+#define EP6_IRQ_FLG            0x0040
+#define EP7_IRQ_FLG            0x0080
+#define RESET_IRQ_FLG          0x0100
+#define SOF_EOP_IRQ_FLG                0x0200
+#define ID_IRQ_FLG             0x4000
+#define VBUS_IRQ_FLG           0x8000
+
+/* USB Host only registers */
+/* ======================= */
+
+/* Host n Control Register */
+#define HOST_CTL_REG(x)                ((x) ? 0xC0A0 : 0xC080)
+
+#define PREAMBLE_EN            0x0080  /* Preamble enable */
+#define SEQ_SEL                        0x0040  /* Data Toggle Sequence Bit Select */
+#define ISO_EN                 0x0010  /* Isochronous enable  */
+#define ARM_EN                 0x0001  /* Arm operation */
+
+/* Host n Interrupt Enable Register */
+#define HOST_IRQ_EN_REG(x)     ((x) ? 0xC0AC : 0xC08C)
+
+#define SOF_EOP_IRQ_EN         0x0200  /* SOF/EOP Interrupt Enable  */
+#define SOF_EOP_TMOUT_IRQ_EN   0x0800  /* SOF/EOP Timeout Interrupt Enable  */
+#define ID_IRQ_EN              0x4000  /* ID interrupt enable */
+#define VBUS_IRQ_EN            0x8000  /* VBUS interrupt enable */
+#define DONE_IRQ_EN            0x0001  /* Done Interrupt Enable  */
+
+/* USB status register */
+#define HOST_STAT_MASK         0x02FD
+#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010)
+#define PORT_SE0_STATUS(x)     ((x) ? 0x0008 : 0x0004)
+
+/* Host Frame Register */
+#define HOST_FRAME_REG(x)      ((x) ? 0xC0B6 : 0xC096)
+
+#define HOST_FRAME_MASK                0x07FF
+
+/* USB Peripheral only registers */
+/* ============================= */
+
+/* Device n Port Sel reg */
+#define DEVICE_N_PORT_SEL(x)   ((x) ? 0xC0A4 : 0xC084)
+
+/* Device n Interrupt Enable Register */
+#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep)   ((dev)                  \
+                                                ? (0x0280 + (ep << 4)) \
+                                                : (0x0200 + (ep << 4)))
+#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep)  ((dev)                  \
+                                                ? (0x0286 + (ep << 4)) \
+                                                : (0x0206 + (ep << 4)))
+
+#define DEVICE_N_ADDRESS(dev)  ((dev) ? (0xC0AE) : (0xC08E))
+
+/* HPI registers */
+/* ============= */
+
+/* HPI Status register */
+#define SOFEOP_FLG(x)          (1 << ((x) ? 12 : 10))
+#define SIEMSG_FLG(x)          (1 << (4 + (x)))
+#define RESET_FLG(x)           ((x) ? 0x0200 : 0x0002)
+#define DONE_FLG(x)            (1 << (2 + (x)))
+#define RESUME_FLG(x)          (1 << (6 + (x)))
+#define MBX_OUT_FLG            0x0001  /* Message out available */
+#define MBX_IN_FLG             0x0100
+#define ID_FLG                 0x4000
+#define VBUS_FLG               0x8000
+
+/* Interrupt routing register */
+#define HPI_IRQ_ROUTING_REG    0x0142
+
+#define HPI_SWAP_ENABLE(x)     ((x) ? 0x0100 : 0x0001)
+#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_TO_HPI_ENABLE(x)  ((x) ? 0x0008 : 0x0004)
+#define RESUME_TO_HPI_ENABLE(x)        ((x) ? 0x0080 : 0x0040)
+#define SOFEOP_TO_HPI_EN(x)    ((x) ? 0x2000 : 0x0800)
+#define SOFEOP_TO_CPU_EN(x)    ((x) ? 0x1000 : 0x0400)
+#define ID_TO_HPI_ENABLE       0x4000
+#define VBUS_TO_HPI_ENABLE     0x8000
+
+/* SIE msg registers */
+#define SIEMSG_REG(x)          ((x) ? 0x0148 : 0x0144)
+
+#define HUSB_TDListDone                0x1000
+
+#define SUSB_EP0_MSG           0x0001
+#define SUSB_EP1_MSG           0x0002
+#define SUSB_EP2_MSG           0x0004
+#define SUSB_EP3_MSG           0x0008
+#define SUSB_EP4_MSG           0x0010
+#define SUSB_EP5_MSG           0x0020
+#define SUSB_EP6_MSG           0x0040
+#define SUSB_EP7_MSG           0x0080
+#define SUSB_RST_MSG           0x0100
+#define SUSB_SOF_MSG           0x0200
+#define SUSB_CFG_MSG           0x0400
+#define SUSB_SUS_MSG           0x0800
+#define SUSB_ID_MSG            0x4000
+#define SUSB_VBUS_MSG          0x8000
+
+/* BIOS interrupt routines */
+
+#define SUSBx_RECEIVE_INT(x)   ((x) ? 97 : 81)
+#define SUSBx_SEND_INT(x)      ((x) ? 96 : 80)
+
+#define SUSBx_DEV_DESC_VEC(x)  ((x) ? 0x00D4 : 0x00B4)
+#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6)
+#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8)
+
+#define CY_HCD_BUF_ADDR                0x500   /* Base address for host */
+#define SIE_TD_SIZE            0x200   /* size of the td list */
+#define SIE_TD_BUF_SIZE                0x400   /* size of the data buffer */
+
+#define SIE_TD_OFFSET(host)    ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0)
+#define SIE_BUF_OFFSET(host)   (SIE_TD_OFFSET(host) + SIE_TD_SIZE)
+
+/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */
+#define CY_UDC_REQ_HEADER_BASE 0x1100
+/* 8- byte request headers for IN/OUT transfers */
+#define CY_UDC_REQ_HEADER_SIZE 8
+
+#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \
+                                        ((ep_num) * CY_UDC_REQ_HEADER_SIZE))
+#define CY_UDC_DESC_BASE_ADDRESS       (CY_UDC_REQ_HEADER_ADDR(8))
+
+#define CY_UDC_BIOS_REPLACE_BASE       0x1800
+#define CY_UDC_REQ_BUFFER_BASE         0x2000
+#define CY_UDC_REQ_BUFFER_SIZE         0x0400
+#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \
+                                        ((ep_num) * CY_UDC_REQ_BUFFER_SIZE))
+
+/* ---------------------------------------------------------------------
+ * Driver data structures
+ */
+
+struct c67x00_device;
+
+/**
+ * struct c67x00_sie - Common data associated with a SIE
+ * @lock: lock to protect this struct and the associated chip registers
+ * @private_data: subdriver dependent data
+ * @irq: subdriver dependent irq handler, set NULL when not used
+ * @dev: link to common driver structure
+ * @sie_num: SIE number on chip, starting from 0
+ * @mode: SIE mode (host/peripheral/otg/not used)
+ */
+struct c67x00_sie {
+       /* Entries to be used by the subdrivers */
+       spinlock_t lock;        /* protect this structure */
+       void *private_data;
+       void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg);
+
+       /* Read only: */
+       struct c67x00_device *dev;
+       int sie_num;
+       int mode;
+};
+
+#define sie_dev(s)     (&(s)->dev->pdev->dev)
+
+/**
+ * struct c67x00_lcp
+ */
+struct c67x00_lcp {
+       /* Internal use only */
+       struct mutex mutex;
+       struct completion msg_received;
+       u16 last_msg;
+};
+
+/*
+ * struct c67x00_hpi
+ */
+struct c67x00_hpi {
+       void __iomem *base;
+       int regstep;
+       spinlock_t lock;
+       struct c67x00_lcp lcp;
+};
+
+#define C67X00_SIES    2
+#define C67X00_PORTS   2
+
+/**
+ * struct c67x00_device - Common data associated with a c67x00 instance
+ * @hpi: hpi addresses
+ * @sie: array of sie's on this chip
+ * @pdev: platform device of instance
+ * @pdata: configuration provided by the platform
+ */
+struct c67x00_device {
+       struct c67x00_hpi hpi;
+       struct c67x00_sie sie[C67X00_SIES];
+       struct platform_device *pdev;
+       struct c67x00_platform_data *pdata;
+};
+
+/* ---------------------------------------------------------------------
+ * Low level interface functions
+ */
+
+/* Host Port Interface (HPI) functions */
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev);
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev);
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie);
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie);
+
+/* General functions */
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num);
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie);
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits);
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie);
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+                             void *data, int len);
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+                            void *data, int len);
+
+/* Host specific functions */
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value);
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port);
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr);
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie);
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie);
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
+
+/* Called by c67x00_irq to handle lcp interrupts */
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
+
+/* Setup and teardown */
+void c67x00_ll_init(struct c67x00_device *dev);
+void c67x00_ll_release(struct c67x00_device *dev);
+int c67x00_ll_reset(struct c67x00_device *dev);
+
+#endif                         /* _USB_C67X00_H */
index e819e5359d5765e1d2e1540432a6aa4981fa5d0a..3e69266e1f4db327c64f90d693aec503c887722b 100644 (file)
@@ -394,7 +394,9 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
        if (!io->urbs)
                goto nomem;
 
-       urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
+       urb_flags = URB_NO_INTERRUPT;
+       if (dma)
+               urb_flags |= URB_NO_TRANSFER_DMA_MAP;
        if (usb_pipein(pipe))
                urb_flags |= URB_SHORT_NOT_OK;
 
index f7b54651dd42eb77ccab5a29bae693c4570c6a7d..6e784d2db42324a91995732fc82f7c16f32201c7 100644 (file)
@@ -231,6 +231,26 @@ config SUPERH_BUILT_IN_M66592
           However, this problem is improved if change a value of
           NET_IP_ALIGN to 4.
 
+config USB_GADGET_PXA27X
+       boolean "PXA 27x"
+       depends on ARCH_PXA && PXA27x
+       help
+          Intel's PXA 27x series XScale ARM v5TE processors include
+          an integrated full speed USB 1.1 device controller.
+
+          It has up to 23 endpoints, as well as endpoint zero (for
+          control transfers).
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "pxa27x_udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_PXA27X
+       tristate
+       depends on USB_GADGET_PXA27X
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_GOKU
        boolean "Toshiba TC86C001 'Goku-S'"
        depends on PCI
index c3aab80b6c76e33095556539f15f2377a14d8adf..12357255d740a6a04e287839b31f47ee7bd8bf54 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_DUMMY_HCD)     += dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)      += net2280.o
 obj-$(CONFIG_USB_AMD5536UDC)   += amd5536udc.o
 obj-$(CONFIG_USB_PXA2XX)       += pxa2xx_udc.o
+obj-$(CONFIG_USB_PXA27X)       += pxa27x_udc.o
 obj-$(CONFIG_USB_GOKU)         += goku_udc.o
 obj-$(CONFIG_USB_OMAP)         += omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)      += lh7a40x_udc.o
index bb93bdd7659315da5707b2ae11e73aecac979996..8d61ea67a8174a801d1ee0f8e902b2239ff53b70 100644 (file)
@@ -235,10 +235,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define        DEV_CONFIG_CDC
 #endif
 
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define DEV_CONFIG_CDC
-#endif
-
 #ifdef CONFIG_USB_GADGET_S3C2410
 #define DEV_CONFIG_CDC
 #endif
@@ -270,6 +266,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define        DEV_CONFIG_SUBSET
 #endif
 
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define        DEV_CONFIG_SUBSET
+#endif
+
 #ifdef CONFIG_USB_GADGET_SUPERH
 #define        DEV_CONFIG_SUBSET
 #endif
index bf3f946fd45544e04cc1549ab68d71f2f2b8f0f2..47bb9f09a1aa1c698dea76218bbe4fc589917989 100644 (file)
@@ -2307,6 +2307,29 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
        return rc;
 }
 
+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+       int     rc;
+
+       DBG(fsg, "bulk-in set wedge\n");
+       rc = usb_ep_set_wedge(fsg->bulk_in);
+       if (rc == -EAGAIN)
+               VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+       while (rc != 0) {
+               if (rc != -EAGAIN) {
+                       WARN(fsg, "usb_ep_set_wedge -> %d\n", rc);
+                       rc = 0;
+                       break;
+               }
+
+               /* Wait for a short time and then try again */
+               if (msleep_interruptible(100) != 0)
+                       return -EINTR;
+               rc = usb_ep_set_wedge(fsg->bulk_in);
+       }
+       return rc;
+}
+
 static int pad_with_zeros(struct fsg_dev *fsg)
 {
        struct fsg_buffhd       *bh = fsg->next_buffhd_to_fill;
@@ -2957,7 +2980,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
                 * We aren't required to halt the OUT endpoint; instead
                 * we can simply accept and discard any data received
                 * until the next reset. */
-               halt_bulk_in_endpoint(fsg);
+               wedge_bulk_in_endpoint(fsg);
                set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
                return -EINVAL;
        }
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
new file mode 100644 (file)
index 0000000..75eba20
--- /dev/null
@@ -0,0 +1,2404 @@
+/*
+ * Handles the Intel 27x USB Device Controller (UDC)
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/hardware.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/arch/udc.h>
+
+#include "pxa27x_udc.h"
+
+/*
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x
+ * series processors.
+ *
+ * Such controller drivers work with a gadget driver.  The gadget driver
+ * returns descriptors, implements configuration and data protocols used
+ * by the host to interact with this device, and allocates endpoints to
+ * the different protocol interfaces.  The controller driver virtualizes
+ * usb hardware so that the gadget drivers will be more portable.
+ *
+ * This UDC hardware wants to implement a bit too much USB protocol. The
+ * biggest issues are:  that the endpoints have to be set up before the
+ * controller can be enabled (minor, and not uncommon); and each endpoint
+ * can only have one configuration, interface and alternative interface
+ * number (major, and very unusual). Once set up, these cannot be changed
+ * without a controller reset.
+ *
+ * The workaround is to setup all combinations necessary for the gadgets which
+ * will work with this driver. This is done in pxa_udc structure, statically.
+ * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep.
+ * (You could modify this if needed.  Some drivers have a "fifo_mode" module
+ * parameter to facilitate such changes.)
+ *
+ * The combinations have been tested with these gadgets :
+ *  - zero gadget
+ *  - file storage gadget
+ *  - ether gadget
+ *
+ * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is
+ * made of UDC's double buffering either. USB "On-The-Go" is not implemented.
+ *
+ * All the requests are handled the same way :
+ *  - the drivers tries to handle the request directly to the IO
+ *  - if the IO fifo is not big enough, the remaining is send/received in
+ *    interrupt handling.
+ */
+
+#define        DRIVER_VERSION  "2008-04-18"
+#define        DRIVER_DESC     "PXA 27x USB Device Controller driver"
+
+static const char driver_name[] = "pxa27x_udc";
+static struct pxa_udc *the_controller;
+
+static void handle_ep(struct pxa_ep *ep);
+
+/*
+ * Debug filesystem
+ */
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+static int state_dbg_show(struct seq_file *s, void *p)
+{
+       struct pxa_udc *udc = s->private;
+       int pos = 0, ret;
+       u32 tmp;
+
+       ret = -ENODEV;
+       if (!udc->driver)
+               goto out;
+
+       /* basic device status */
+       pos += seq_printf(s, DRIVER_DESC "\n"
+                        "%s version: %s\nGadget driver: %s\n",
+                        driver_name, DRIVER_VERSION,
+                        udc->driver ? udc->driver->driver.name : "(none)");
+
+       tmp = udc_readl(udc, UDCCR);
+       pos += seq_printf(s,
+                        "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), "
+                        "con=%d,inter=%d,altinter=%d\n", tmp,
+                        (tmp & UDCCR_OEN) ? " oen":"",
+                        (tmp & UDCCR_AALTHNP) ? " aalthnp":"",
+                        (tmp & UDCCR_AHNP) ? " rem" : "",
+                        (tmp & UDCCR_BHNP) ? " rstir" : "",
+                        (tmp & UDCCR_DWRE) ? " dwre" : "",
+                        (tmp & UDCCR_SMAC) ? " smac" : "",
+                        (tmp & UDCCR_EMCE) ? " emce" : "",
+                        (tmp & UDCCR_UDR) ? " udr" : "",
+                        (tmp & UDCCR_UDA) ? " uda" : "",
+                        (tmp & UDCCR_UDE) ? " ude" : "",
+                        (tmp & UDCCR_ACN) >> UDCCR_ACN_S,
+                        (tmp & UDCCR_AIN) >> UDCCR_AIN_S,
+                        (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S);
+       /* registers for device and ep0 */
+       pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
+                       udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
+       pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
+                       udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1));
+       pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR));
+       pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, "
+                       "reconfig=%lu\n",
+                       udc->stats.irqs_reset, udc->stats.irqs_suspend,
+                       udc->stats.irqs_resume, udc->stats.irqs_reconfig);
+
+       ret = 0;
+out:
+       return ret;
+}
+
+static int queues_dbg_show(struct seq_file *s, void *p)
+{
+       struct pxa_udc *udc = s->private;
+       struct pxa_ep *ep;
+       struct pxa27x_request *req;
+       int pos = 0, i, maxpkt, ret;
+
+       ret = -ENODEV;
+       if (!udc->driver)
+               goto out;
+
+       /* dump endpoint queues */
+       for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+               ep = &udc->pxa_ep[i];
+               maxpkt = ep->fifo_size;
+               pos += seq_printf(s,  "%-12s max_pkt=%d %s\n",
+                               EPNAME(ep), maxpkt, "pio");
+
+               if (list_empty(&ep->queue)) {
+                       pos += seq_printf(s, "\t(nothing queued)\n");
+                       continue;
+               }
+
+               list_for_each_entry(req, &ep->queue, queue) {
+                       pos += seq_printf(s,  "\treq %p len %d/%d buf %p\n",
+                                       &req->req, req->req.actual,
+                                       req->req.length, req->req.buf);
+               }
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
+static int eps_dbg_show(struct seq_file *s, void *p)
+{
+       struct pxa_udc *udc = s->private;
+       struct pxa_ep *ep;
+       int pos = 0, i, ret;
+       u32 tmp;
+
+       ret = -ENODEV;
+       if (!udc->driver)
+               goto out;
+
+       ep = &udc->pxa_ep[0];
+       tmp = udc_ep_readl(ep, UDCCSR);
+       pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp,
+                        (tmp & UDCCSR0_SA) ? " sa" : "",
+                        (tmp & UDCCSR0_RNE) ? " rne" : "",
+                        (tmp & UDCCSR0_FST) ? " fst" : "",
+                        (tmp & UDCCSR0_SST) ? " sst" : "",
+                        (tmp & UDCCSR0_DME) ? " dme" : "",
+                        (tmp & UDCCSR0_IPR) ? " ipr" : "",
+                        (tmp & UDCCSR0_OPC) ? " opc" : "");
+       for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+               ep = &udc->pxa_ep[i];
+               tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR);
+               pos += seq_printf(s, "%-12s: "
+                               "IN %lu(%lu reqs), OUT %lu(%lu reqs), "
+                               "irqs=%lu, udccr=0x%08x, udccsr=0x%03x, "
+                               "udcbcr=%d\n",
+                               EPNAME(ep),
+                               ep->stats.in_bytes, ep->stats.in_ops,
+                               ep->stats.out_bytes, ep->stats.out_ops,
+                               ep->stats.irqs,
+                               tmp, udc_ep_readl(ep, UDCCSR),
+                               udc_ep_readl(ep, UDCBCR));
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
+static int eps_dbg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, eps_dbg_show, inode->i_private);
+}
+
+static int queues_dbg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, queues_dbg_show, inode->i_private);
+}
+
+static int state_dbg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, state_dbg_show, inode->i_private);
+}
+
+static const struct file_operations state_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = state_dbg_open,
+       .llseek         = seq_lseek,
+       .read           = seq_read,
+       .release        = single_release,
+};
+
+static const struct file_operations queues_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = queues_dbg_open,
+       .llseek         = seq_lseek,
+       .read           = seq_read,
+       .release        = single_release,
+};
+
+static const struct file_operations eps_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = eps_dbg_open,
+       .llseek         = seq_lseek,
+       .read           = seq_read,
+       .release        = single_release,
+};
+
+static void pxa_init_debugfs(struct pxa_udc *udc)
+{
+       struct dentry *root, *state, *queues, *eps;
+
+       root = debugfs_create_dir(udc->gadget.name, NULL);
+       if (IS_ERR(root) || !root)
+               goto err_root;
+
+       state = debugfs_create_file("udcstate", 0400, root, udc,
+                       &state_dbg_fops);
+       if (!state)
+               goto err_state;
+       queues = debugfs_create_file("queues", 0400, root, udc,
+                       &queues_dbg_fops);
+       if (!queues)
+               goto err_queues;
+       eps = debugfs_create_file("epstate", 0400, root, udc,
+                       &eps_dbg_fops);
+       if (!queues)
+               goto err_eps;
+
+       udc->debugfs_root = root;
+       udc->debugfs_state = state;
+       udc->debugfs_queues = queues;
+       udc->debugfs_eps = eps;
+       return;
+err_eps:
+       debugfs_remove(eps);
+err_queues:
+       debugfs_remove(queues);
+err_state:
+       debugfs_remove(root);
+err_root:
+       dev_err(udc->dev, "debugfs is not available\n");
+}
+
+static void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+       debugfs_remove(udc->debugfs_eps);
+       debugfs_remove(udc->debugfs_queues);
+       debugfs_remove(udc->debugfs_state);
+       debugfs_remove(udc->debugfs_root);
+       udc->debugfs_eps = NULL;
+       udc->debugfs_queues = NULL;
+       udc->debugfs_state = NULL;
+       udc->debugfs_root = NULL;
+}
+
+#else
+static inline void pxa_init_debugfs(struct pxa_udc *udc)
+{
+}
+
+static inline void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+}
+#endif
+
+/**
+ * is_match_usb_pxa - check if usb_ep and pxa_ep match
+ * @udc_usb_ep: usb endpoint
+ * @ep: pxa endpoint
+ * @config: configuration required in pxa_ep
+ * @interface: interface required in pxa_ep
+ * @altsetting: altsetting required in pxa_ep
+ *
+ * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise
+ */
+static int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep,
+               int config, int interface, int altsetting)
+{
+       if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr)
+               return 0;
+       if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in)
+               return 0;
+       if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type)
+               return 0;
+       if ((ep->config != config) || (ep->interface != interface)
+                       || (ep->alternate != altsetting))
+               return 0;
+       return 1;
+}
+
+/**
+ * find_pxa_ep - find pxa_ep structure matching udc_usb_ep
+ * @udc: pxa udc
+ * @udc_usb_ep: udc_usb_ep structure
+ *
+ * Match udc_usb_ep and all pxa_ep available, to see if one matches.
+ * This is necessary because of the strong pxa hardware restriction requiring
+ * that once pxa endpoints are initialized, their configuration is freezed, and
+ * no change can be made to their address, direction, or in which configuration,
+ * interface or altsetting they are active ... which differs from more usual
+ * models which have endpoints be roughly just addressable fifos, and leave
+ * configuration events up to gadget drivers (like all control messages).
+ *
+ * Note that there is still a blurred point here :
+ *   - we rely on UDCCR register "active interface" and "active altsetting".
+ *     This is a nonsense in regard of USB spec, where multiple interfaces are
+ *     active at the same time.
+ *   - if we knew for sure that the pxa can handle multiple interface at the
+ *     same time, assuming Intel's Developer Guide is wrong, this function
+ *     should be reviewed, and a cache of couples (iface, altsetting) should
+ *     be kept in the pxa_udc structure. In this case this function would match
+ *     against the cache of couples instead of the "last altsetting" set up.
+ *
+ * Returns the matched pxa_ep structure or NULL if none found
+ */
+static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc,
+               struct udc_usb_ep *udc_usb_ep)
+{
+       int i;
+       struct pxa_ep *ep;
+       int cfg = udc->config;
+       int iface = udc->last_interface;
+       int alt = udc->last_alternate;
+
+       if (udc_usb_ep == &udc->udc_usb_ep[0])
+               return &udc->pxa_ep[0];
+
+       for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+               ep = &udc->pxa_ep[i];
+               if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt))
+                       return ep;
+       }
+       return NULL;
+}
+
+/**
+ * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep
+ * @udc: pxa udc
+ *
+ * Context: in_interrupt()
+ *
+ * Updates all pxa_ep fields in udc_usb_ep structures, if this field was
+ * previously set up (and is not NULL). The update is necessary is a
+ * configuration change or altsetting change was issued by the USB host.
+ */
+static void update_pxa_ep_matches(struct pxa_udc *udc)
+{
+       int i;
+       struct udc_usb_ep *udc_usb_ep;
+
+       for (i = 1; i < NR_USB_ENDPOINTS; i++) {
+               udc_usb_ep = &udc->udc_usb_ep[i];
+               if (udc_usb_ep->pxa_ep)
+                       udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep);
+       }
+}
+
+/**
+ * pio_irq_enable - Enables irq generation for one endpoint
+ * @ep: udc endpoint
+ */
+static void pio_irq_enable(struct pxa_ep *ep)
+{
+       struct pxa_udc *udc = ep->dev;
+       int index = EPIDX(ep);
+       u32 udcicr0 = udc_readl(udc, UDCICR0);
+       u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+       if (index < 16)
+               udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2)));
+       else
+               udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2)));
+}
+
+/**
+ * pio_irq_disable - Disables irq generation for one endpoint
+ * @ep: udc endpoint
+ * @index: endpoint number
+ */
+static void pio_irq_disable(struct pxa_ep *ep)
+{
+       struct pxa_udc *udc = ep->dev;
+       int index = EPIDX(ep);
+       u32 udcicr0 = udc_readl(udc, UDCICR0);
+       u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+       if (index < 16)
+               udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2)));
+       else
+               udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2)));
+}
+
+/**
+ * udc_set_mask_UDCCR - set bits in UDCCR
+ * @udc: udc device
+ * @mask: bits to set in UDCCR
+ *
+ * Sets bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+       u32 udccr = udc_readl(udc, UDCCR);
+       udc_writel(udc, UDCCR,
+                       (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * udc_clear_mask_UDCCR - clears bits in UDCCR
+ * @udc: udc device
+ * @mask: bit to clear in UDCCR
+ *
+ * Clears bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+       u32 udccr = udc_readl(udc, UDCCR);
+       udc_writel(udc, UDCCR,
+                       (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * ep_count_bytes_remain - get how many bytes in udc endpoint
+ * @ep: udc endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP)
+ */
+static int ep_count_bytes_remain(struct pxa_ep *ep)
+{
+       if (ep->dir_in)
+               return -EOPNOTSUPP;
+       return udc_ep_readl(ep, UDCBCR) & 0x3ff;
+}
+
+/**
+ * ep_is_empty - checks if ep has byte ready for reading
+ * @ep: udc endpoint
+ *
+ * If endpoint is the control endpoint, checks if there are bytes in the
+ * control endpoint fifo. If endpoint is a data endpoint, checks if bytes
+ * are ready for reading on OUT endpoint.
+ *
+ * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint
+ */
+static int ep_is_empty(struct pxa_ep *ep)
+{
+       int ret;
+
+       if (!is_ep0(ep) && ep->dir_in)
+               return -EOPNOTSUPP;
+       if (is_ep0(ep))
+               ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE);
+       else
+               ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE);
+       return ret;
+}
+
+/**
+ * ep_is_full - checks if ep has place to write bytes
+ * @ep: udc endpoint
+ *
+ * If endpoint is not the control endpoint and is an IN endpoint, checks if
+ * there is place to write bytes into the endpoint.
+ *
+ * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint
+ */
+static int ep_is_full(struct pxa_ep *ep)
+{
+       if (is_ep0(ep))
+               return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR);
+       if (!ep->dir_in)
+               return -EOPNOTSUPP;
+       return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF));
+}
+
+/**
+ * epout_has_pkt - checks if OUT endpoint fifo has a packet available
+ * @ep: pxa endpoint
+ *
+ * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep.
+ */
+static int epout_has_pkt(struct pxa_ep *ep)
+{
+       if (!is_ep0(ep) && ep->dir_in)
+               return -EOPNOTSUPP;
+       if (is_ep0(ep))
+               return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC);
+       return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC);
+}
+
+/**
+ * set_ep0state - Set ep0 automata state
+ * @dev: udc device
+ * @state: state
+ */
+static void set_ep0state(struct pxa_udc *udc, int state)
+{
+       struct pxa_ep *ep = &udc->pxa_ep[0];
+       char *old_stname = EP0_STNAME(udc);
+
+       udc->ep0state = state;
+       ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname,
+               EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR),
+               udc_ep_readl(ep, UDCBCR));
+}
+
+/**
+ * ep0_idle - Put control endpoint into idle state
+ * @dev: udc device
+ */
+static void ep0_idle(struct pxa_udc *dev)
+{
+       set_ep0state(dev, WAIT_FOR_SETUP);
+}
+
+/**
+ * inc_ep_stats_reqs - Update ep stats counts
+ * @ep: physical endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ *
+ */
+static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in)
+{
+       if (is_in)
+               ep->stats.in_ops++;
+       else
+               ep->stats.out_ops++;
+}
+
+/**
+ * inc_ep_stats_bytes - Update ep stats counts
+ * @ep: physical endpoint
+ * @count: bytes transfered on endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ */
+static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
+{
+       if (is_in)
+               ep->stats.in_bytes += count;
+       else
+               ep->stats.out_bytes += count;
+}
+
+/**
+ * pxa_ep_setup - Sets up an usb physical endpoint
+ * @ep: pxa27x physical endpoint
+ *
+ * Find the physical pxa27x ep, and setup its UDCCR
+ */
+static __init void pxa_ep_setup(struct pxa_ep *ep)
+{
+       u32 new_udccr;
+
+       new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN)
+               | ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN)
+               | ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN)
+               | ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN)
+               | ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET)
+               | ((ep->dir_in) ? UDCCONR_ED : 0)
+               | ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS)
+               | UDCCONR_EE;
+
+       udc_ep_writel(ep, UDCCR, new_udccr);
+}
+
+/**
+ * pxa_eps_setup - Sets up all usb physical endpoints
+ * @dev: udc device
+ *
+ * Setup all pxa physical endpoints, except ep0
+ */
+static __init void pxa_eps_setup(struct pxa_udc *dev)
+{
+       unsigned int i;
+
+       dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev);
+
+       for (i = 1; i < NR_PXA_ENDPOINTS; i++)
+               pxa_ep_setup(&dev->pxa_ep[i]);
+}
+
+/**
+ * pxa_ep_alloc_request - Allocate usb request
+ * @_ep: usb endpoint
+ * @gfp_flags:
+ *
+ * For the pxa27x, these can just wrap kmalloc/kfree.  gadget drivers
+ * must still pass correctly initialized endpoints, since other controller
+ * drivers may care about how it's currently set up (dma issues etc).
+  */
+static struct usb_request *
+pxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+       struct pxa27x_request *req;
+
+       req = kzalloc(sizeof *req, gfp_flags);
+       if (!req || !_ep)
+               return NULL;
+
+       INIT_LIST_HEAD(&req->queue);
+       req->in_use = 0;
+       req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+       return &req->req;
+}
+
+/**
+ * pxa_ep_free_request - Free usb request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Wrapper around kfree to free _req
+ */
+static void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct pxa27x_request *req;
+
+       req = container_of(_req, struct pxa27x_request, req);
+       WARN_ON(!list_empty(&req->queue));
+       kfree(req);
+}
+
+/**
+ * ep_add_request - add a request to the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Queues the request in the endpoint's queue, and enables the interrupts
+ * on the endpoint.
+ */
+static void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       if (unlikely(!req))
+               return;
+       ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+               req->req.length, udc_ep_readl(ep, UDCCSR));
+
+       req->in_use = 1;
+       list_add_tail(&req->queue, &ep->queue);
+       pio_irq_enable(ep);
+}
+
+/**
+ * ep_del_request - removes a request from the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Unqueue the request from the endpoint's queue. If there are no more requests
+ * on the endpoint, and if it's not the control endpoint, interrupts are
+ * disabled on the endpoint.
+ */
+static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       if (unlikely(!req))
+               return;
+       ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+               req->req.length, udc_ep_readl(ep, UDCCSR));
+
+       list_del_init(&req->queue);
+       req->in_use = 0;
+       if (!is_ep0(ep) && list_empty(&ep->queue))
+               pio_irq_disable(ep);
+}
+
+/**
+ * req_done - Complete an usb request
+ * @ep: pxa physical endpoint
+ * @req: pxa request
+ * @status: usb request status sent to gadget API
+ *
+ * Context: ep->lock held
+ *
+ * Retire a pxa27x usb request. Endpoint must be locked.
+ */
+static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
+{
+       ep_del_request(ep, req);
+       if (likely(req->req.status == -EINPROGRESS))
+               req->req.status = status;
+       else
+               status = req->req.status;
+
+       if (status && status != -ESHUTDOWN)
+               ep_dbg(ep, "complete req %p stat %d len %u/%u\n",
+                       &req->req, status,
+                       req->req.actual, req->req.length);
+
+       req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
+}
+
+/**
+ * ep_end_out_req - Ends control endpoint in request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint in request (completes usb request).
+ */
+static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       inc_ep_stats_reqs(ep, !USB_DIR_IN);
+       req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_out_req - Ends control endpoint in request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint in request (completes usb request), and puts
+ * control endpoint into idle state
+ */
+static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       set_ep0state(ep->dev, OUT_STATUS_STAGE);
+       ep_end_out_req(ep, req);
+       ep0_idle(ep->dev);
+}
+
+/**
+ * ep_end_in_req - Ends endpoint out request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint out request (completes usb request).
+ */
+static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       inc_ep_stats_reqs(ep, USB_DIR_IN);
+       req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_in_req - Ends control endpoint out request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint out request (completes usb request), and puts
+ * control endpoint into status state
+ */
+static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       struct pxa_udc *udc = ep->dev;
+
+       set_ep0state(udc, IN_STATUS_STAGE);
+       ep_end_in_req(ep, req);
+}
+
+/**
+ * nuke - Dequeue all requests
+ * @ep: pxa endpoint
+ * @status: usb request status
+ *
+ * Context: ep->lock held
+ *
+ * Dequeues all requests on an endpoint. As a side effect, interrupts will be
+ * disabled on that endpoint (because no more requests).
+ */
+static void nuke(struct pxa_ep *ep, int status)
+{
+       struct pxa27x_request *req;
+
+       while (!list_empty(&ep->queue)) {
+               req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+               req_done(ep, req, status);
+       }
+}
+
+/**
+ * read_packet - transfer 1 packet from an OUT endpoint into request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Takes bytes from OUT endpoint and transfers them info the usb request.
+ * If there is less space in request than bytes received in OUT endpoint,
+ * bytes are left in the OUT endpoint.
+ *
+ * Returns how many bytes were actually transfered
+ */
+static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       u32 *buf;
+       int bytes_ep, bufferspace, count, i;
+
+       bytes_ep = ep_count_bytes_remain(ep);
+       bufferspace = req->req.length - req->req.actual;
+
+       buf = (u32 *)(req->req.buf + req->req.actual);
+       prefetchw(buf);
+
+       if (likely(!ep_is_empty(ep)))
+               count = min(bytes_ep, bufferspace);
+       else /* zlp */
+               count = 0;
+
+       for (i = count; i > 0; i -= 4)
+               *buf++ = udc_ep_readl(ep, UDCDR);
+       req->req.actual += count;
+
+       udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+
+       return count;
+}
+
+/**
+ * write_packet - transfer 1 packet from request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ * @max: max bytes that fit into endpoint
+ *
+ * Takes bytes from usb request, and transfers them into the physical
+ * endpoint. If there are no bytes to transfer, doesn't write anything
+ * to physical endpoint.
+ *
+ * Returns how many bytes were actually transfered.
+ */
+static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req,
+                       unsigned int max)
+{
+       int length, count, remain, i;
+       u32 *buf;
+       u8 *buf_8;
+
+       buf = (u32 *)(req->req.buf + req->req.actual);
+       prefetch(buf);
+
+       length = min(req->req.length - req->req.actual, max);
+       req->req.actual += length;
+
+       remain = length & 0x3;
+       count = length & ~(0x3);
+       for (i = count; i > 0 ; i -= 4)
+               udc_ep_writel(ep, UDCDR, *buf++);
+
+       buf_8 = (u8 *)buf;
+       for (i = remain; i > 0; i--)
+               udc_ep_writeb(ep, UDCDR, *buf_8++);
+
+       ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain,
+               udc_ep_readl(ep, UDCCSR));
+
+       return length;
+}
+
+/**
+ * read_fifo - Transfer packets from OUT endpoint into usb request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Unload as many packets as possible from the fifo we use for usb OUT
+ * transfers and put them into the request. Caller should have made sure
+ * there's at least one packet ready.
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if the request completed, 0 otherwise
+ */
+static int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       int count, is_short, completed = 0;
+
+       while (epout_has_pkt(ep)) {
+               count = read_packet(ep, req);
+               inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+               is_short = (count < ep->fifo_size);
+               ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+                       udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+                       &req->req, req->req.actual, req->req.length);
+
+               /* completion */
+               if (is_short || req->req.actual == req->req.length) {
+                       completed = 1;
+                       break;
+               }
+               /* finished that packet.  the next one may be waiting... */
+       }
+       return completed;
+}
+
+/**
+ * write_fifo - transfer packets from usb request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: pxa usb request
+ *
+ * Write to an IN endpoint fifo, as many packets as possible.
+ * irqs will use this to write the rest later.
+ * caller guarantees at least one packet buffer is ready (or a zlp).
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if request fully transfered, 0 if partial transfer
+ */
+static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       unsigned max;
+       int count, is_short, is_last = 0, completed = 0, totcount = 0;
+       u32 udccsr;
+
+       max = ep->fifo_size;
+       do {
+               is_short = 0;
+
+               udccsr = udc_ep_readl(ep, UDCCSR);
+               if (udccsr & UDCCSR_PC) {
+                       ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
+                               udccsr);
+                       udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+               }
+               if (udccsr & UDCCSR_TRN) {
+                       ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n",
+                               udccsr);
+                       udc_ep_writel(ep, UDCCSR, UDCCSR_TRN);
+               }
+
+               count = write_packet(ep, req, max);
+               inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+               totcount += count;
+
+               /* last packet is usually short (or a zlp) */
+               if (unlikely(count < max)) {
+                       is_last = 1;
+                       is_short = 1;
+               } else {
+                       if (likely(req->req.length > req->req.actual)
+                                       || req->req.zero)
+                               is_last = 0;
+                       else
+                               is_last = 1;
+                       /* interrupt/iso maxpacket may not fill the fifo */
+                       is_short = unlikely(max < ep->fifo_size);
+               }
+
+               if (is_short)
+                       udc_ep_writel(ep, UDCCSR, UDCCSR_SP);
+
+               /* requests complete when all IN data is in the FIFO */
+               if (is_last) {
+                       completed = 1;
+                       break;
+               }
+       } while (!ep_is_full(ep));
+
+       ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n",
+                       totcount, is_last ? "/L" : "", is_short ? "/S" : "",
+                       req->req.length - req->req.actual, &req->req);
+
+       return completed;
+}
+
+/**
+ * read_ep0_fifo - Transfer packets from control endpoint into usb request
+ * @ep: control endpoint
+ * @req: pxa usb request
+ *
+ * Special ep0 version of the above read_fifo. Reads as many bytes from control
+ * endpoint as can be read, and stores them into usb request (limited by request
+ * maximum length).
+ *
+ * Returns 0 if usb request only partially filled, 1 if fully filled
+ */
+static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       int count, is_short, completed = 0;
+
+       while (epout_has_pkt(ep)) {
+               count = read_packet(ep, req);
+               udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+               inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+               is_short = (count < ep->fifo_size);
+               ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+                       udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+                       &req->req, req->req.actual, req->req.length);
+
+               if (is_short || req->req.actual >= req->req.length) {
+                       completed = 1;
+                       break;
+               }
+       }
+
+       return completed;
+}
+
+/**
+ * write_ep0_fifo - Send a request to control endpoint (ep0 in)
+ * @ep: control endpoint
+ * @req: request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Sends a request (or a part of the request) to the control endpoint (ep0 in).
+ * If the request doesn't fit, the remaining part will be sent from irq.
+ * The request is considered fully written only if either :
+ *   - last write transfered all remaining bytes, but fifo was not fully filled
+ *   - last write was a 0 length write
+ *
+ * Returns 1 if request fully written, 0 if request only partially sent
+ */
+static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+       unsigned        count;
+       int             is_last, is_short;
+
+       count = write_packet(ep, req, EP0_FIFO_SIZE);
+       inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+
+       is_short = (count < EP0_FIFO_SIZE);
+       is_last = ((count == 0) || (count < EP0_FIFO_SIZE));
+
+       /* Sends either a short packet or a 0 length packet */
+       if (unlikely(is_short))
+               udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR);
+
+       ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n",
+               count, is_short ? "/S" : "", is_last ? "/L" : "",
+               req->req.length - req->req.actual,
+               &req->req, udc_ep_readl(ep, UDCCSR));
+
+       return is_last;
+}
+
+/**
+ * pxa_ep_queue - Queue a request into an IN endpoint
+ * @_ep: usb endpoint
+ * @_req: usb request
+ * @gfp_flags: flags
+ *
+ * Context: normally called when !in_interrupt, but callable when in_interrupt()
+ * in the special case of ep0 setup :
+ *   (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue)
+ *
+ * Returns 0 if succedeed, error otherwise
+ */
+static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+                       gfp_t gfp_flags)
+{
+       struct udc_usb_ep       *udc_usb_ep;
+       struct pxa_ep           *ep;
+       struct pxa27x_request   *req;
+       struct pxa_udc          *dev;
+       unsigned long           flags;
+       int                     rc = 0;
+       int                     is_first_req;
+       unsigned                length;
+
+       req = container_of(_req, struct pxa27x_request, req);
+       udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+       if (unlikely(!_req || !_req->complete || !_req->buf))
+               return -EINVAL;
+
+       if (unlikely(!_ep))
+               return -EINVAL;
+
+       dev = udc_usb_ep->dev;
+       ep = udc_usb_ep->pxa_ep;
+       if (unlikely(!ep))
+               return -EINVAL;
+
+       dev = ep->dev;
+       if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+               ep_dbg(ep, "bogus device state\n");
+               return -ESHUTDOWN;
+       }
+
+       /* iso is always one packet per request, that's the only way
+        * we can report per-packet status.  that also helps with dma.
+        */
+       if (unlikely(EPXFERTYPE_is_ISO(ep)
+                       && req->req.length > ep->fifo_size))
+               return -EMSGSIZE;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       is_first_req = list_empty(&ep->queue);
+       ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
+                       _req, is_first_req ? "yes" : "no",
+                       _req->length, _req->buf);
+
+       if (!ep->enabled) {
+               _req->status = -ESHUTDOWN;
+               rc = -ESHUTDOWN;
+               goto out;
+       }
+
+       if (req->in_use) {
+               ep_err(ep, "refusing to queue req %p (already queued)\n", req);
+               goto out;
+       }
+
+       length = _req->length;
+       _req->status = -EINPROGRESS;
+       _req->actual = 0;
+
+       ep_add_request(ep, req);
+
+       if (is_ep0(ep)) {
+               switch (dev->ep0state) {
+               case WAIT_ACK_SET_CONF_INTERF:
+                       if (length == 0) {
+                               ep_end_in_req(ep, req);
+                       } else {
+                               ep_err(ep, "got a request of %d bytes while"
+                                       "in state WATI_ACK_SET_CONF_INTERF\n",
+                                       length);
+                               ep_del_request(ep, req);
+                               rc = -EL2HLT;
+                       }
+                       ep0_idle(ep->dev);
+                       break;
+               case IN_DATA_STAGE:
+                       if (!ep_is_full(ep))
+                               if (write_ep0_fifo(ep, req))
+                                       ep0_end_in_req(ep, req);
+                       break;
+               case OUT_DATA_STAGE:
+                       if ((length == 0) || !epout_has_pkt(ep))
+                               if (read_ep0_fifo(ep, req))
+                                       ep0_end_out_req(ep, req);
+                       break;
+               default:
+                       ep_err(ep, "odd state %s to send me a request\n",
+                               EP0_STNAME(ep->dev));
+                       ep_del_request(ep, req);
+                       rc = -EL2HLT;
+                       break;
+               }
+       } else {
+               handle_ep(ep);
+       }
+
+out:
+       spin_unlock_irqrestore(&ep->lock, flags);
+       return rc;
+}
+
+/**
+ * pxa_ep_dequeue - Dequeue one request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Return 0 if no error, -EINVAL or -ECONNRESET otherwise
+ */
+static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct pxa_ep           *ep;
+       struct udc_usb_ep       *udc_usb_ep;
+       struct pxa27x_request   *req;
+       unsigned long           flags;
+       int                     rc;
+
+       if (!_ep)
+               return -EINVAL;
+       udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+       ep = udc_usb_ep->pxa_ep;
+       if (!ep || is_ep0(ep))
+               return -EINVAL;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       /* make sure it's actually queued on this endpoint */
+       list_for_each_entry(req, &ep->queue, queue) {
+               if (&req->req == _req)
+                       break;
+       }
+
+       rc = -EINVAL;
+       if (&req->req != _req)
+               goto out;
+
+       rc = 0;
+       req_done(ep, req, -ECONNRESET);
+out:
+       spin_unlock_irqrestore(&ep->lock, flags);
+       return rc;
+}
+
+/**
+ * pxa_ep_set_halt - Halts operations on one endpoint
+ * @_ep: usb endpoint
+ * @value:
+ *
+ * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise
+ */
+static int pxa_ep_set_halt(struct usb_ep *_ep, int value)
+{
+       struct pxa_ep           *ep;
+       struct udc_usb_ep       *udc_usb_ep;
+       unsigned long flags;
+       int rc;
+
+
+       if (!_ep)
+               return -EINVAL;
+       udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+       ep = udc_usb_ep->pxa_ep;
+       if (!ep || is_ep0(ep))
+               return -EINVAL;
+
+       if (value == 0) {
+               /*
+                * This path (reset toggle+halt) is needed to implement
+                * SET_INTERFACE on normal hardware.  but it can't be
+                * done from software on the PXA UDC, and the hardware
+                * forgets to do it as part of SET_INTERFACE automagic.
+                */
+               ep_dbg(ep, "only host can clear halt\n");
+               return -EROFS;
+       }
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       rc = -EAGAIN;
+       if (ep->dir_in  && (ep_is_full(ep) || !list_empty(&ep->queue)))
+               goto out;
+
+       /* FST, FEF bits are the same for control and non control endpoints */
+       rc = 0;
+       udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF);
+       if (is_ep0(ep))
+               set_ep0state(ep->dev, STALL);
+
+out:
+       spin_unlock_irqrestore(&ep->lock, flags);
+       return rc;
+}
+
+/**
+ * pxa_ep_fifo_status - Get how many bytes in physical endpoint
+ * @_ep: usb endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos.
+ */
+static int pxa_ep_fifo_status(struct usb_ep *_ep)
+{
+       struct pxa_ep           *ep;
+       struct udc_usb_ep       *udc_usb_ep;
+
+       if (!_ep)
+               return -ENODEV;
+       udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+       ep = udc_usb_ep->pxa_ep;
+       if (!ep || is_ep0(ep))
+               return -ENODEV;
+
+       if (ep->dir_in)
+               return -EOPNOTSUPP;
+       if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep))
+               return 0;
+       else
+               return ep_count_bytes_remain(ep) + 1;
+}
+
+/**
+ * pxa_ep_fifo_flush - Flushes one endpoint
+ * @_ep: usb endpoint
+ *
+ * Discards all data in one endpoint(IN or OUT), except control endpoint.
+ */
+static void pxa_ep_fifo_flush(struct usb_ep *_ep)
+{
+       struct pxa_ep           *ep;
+       struct udc_usb_ep       *udc_usb_ep;
+       unsigned long           flags;
+
+       if (!_ep)
+               return;
+       udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+       ep = udc_usb_ep->pxa_ep;
+       if (!ep || is_ep0(ep))
+               return;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       if (unlikely(!list_empty(&ep->queue)))
+               ep_dbg(ep, "called while queue list not empty\n");
+       ep_dbg(ep, "called\n");
+
+       /* for OUT, just read and discard the FIFO contents. */
+       if (!ep->dir_in) {
+               while (!ep_is_empty(ep))
+                       udc_ep_readl(ep, UDCDR);
+       } else {
+               /* most IN status is the same, but ISO can't stall */
+               udc_ep_writel(ep, UDCCSR,
+                               UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN
+                               | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST));
+       }
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       return;
+}
+
+/**
+ * pxa_ep_enable - Enables usb endpoint
+ * @_ep: usb endpoint
+ * @desc: usb endpoint descriptor
+ *
+ * Nothing much to do here, as ep configuration is done once and for all
+ * before udc is enabled. After udc enable, no physical endpoint configuration
+ * can be changed.
+ * Function makes sanity checks and flushes the endpoint.
+ */
+static int pxa_ep_enable(struct usb_ep *_ep,
+       const struct usb_endpoint_descriptor *desc)
+{
+       struct pxa_ep           *ep;
+       struct udc_usb_ep       *udc_usb_ep;
+       struct pxa_udc          *udc;
+
+       if (!_ep || !desc)
+               return -EINVAL;
+
+       udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+       if (udc_usb_ep->pxa_ep) {
+               ep = udc_usb_ep->pxa_ep;
+               ep_warn(ep, "usb_ep %s already enabled, doing nothing\n",
+                       _ep->name);
+       } else {
+               ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep);
+       }
+
+       if (!ep || is_ep0(ep)) {
+               dev_err(udc_usb_ep->dev->dev,
+                       "unable to match pxa_ep for ep %s\n",
+                       _ep->name);
+               return -EINVAL;
+       }
+
+       if ((desc->bDescriptorType != USB_DT_ENDPOINT)
+                       || (ep->type != usb_endpoint_type(desc))) {
+               ep_err(ep, "type mismatch\n");
+               return -EINVAL;
+       }
+
+       if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) {
+               ep_err(ep, "bad maxpacket\n");
+               return -ERANGE;
+       }
+
+       udc_usb_ep->pxa_ep = ep;
+       udc = ep->dev;
+
+       if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+               ep_err(ep, "bogus device state\n");
+               return -ESHUTDOWN;
+       }
+
+       ep->enabled = 1;
+
+       /* flush fifo (mostly for OUT buffers) */
+       pxa_ep_fifo_flush(_ep);
+
+       ep_dbg(ep, "enabled\n");
+       return 0;
+}
+
+/**
+ * pxa_ep_disable - Disable usb endpoint
+ * @_ep: usb endpoint
+ *
+ * Same as for pxa_ep_enable, no physical endpoint configuration can be
+ * changed.
+ * Function flushes the endpoint and related requests.
+ */
+static int pxa_ep_disable(struct usb_ep *_ep)
+{
+       struct pxa_ep           *ep;
+       struct udc_usb_ep       *udc_usb_ep;
+       unsigned long           flags;
+
+       if (!_ep)
+               return -EINVAL;
+
+       udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+       ep = udc_usb_ep->pxa_ep;
+       if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
+               return -EINVAL;
+
+       spin_lock_irqsave(&ep->lock, flags);
+       ep->enabled = 0;
+       nuke(ep, -ESHUTDOWN);
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       pxa_ep_fifo_flush(_ep);
+       udc_usb_ep->pxa_ep = NULL;
+
+       ep_dbg(ep, "disabled\n");
+       return 0;
+}
+
+static struct usb_ep_ops pxa_ep_ops = {
+       .enable         = pxa_ep_enable,
+       .disable        = pxa_ep_disable,
+
+       .alloc_request  = pxa_ep_alloc_request,
+       .free_request   = pxa_ep_free_request,
+
+       .queue          = pxa_ep_queue,
+       .dequeue        = pxa_ep_dequeue,
+
+       .set_halt       = pxa_ep_set_halt,
+       .fifo_status    = pxa_ep_fifo_status,
+       .fifo_flush     = pxa_ep_fifo_flush,
+};
+
+
+/**
+ * pxa_udc_get_frame - Returns usb frame number
+ * @_gadget: usb gadget
+ */
+static int pxa_udc_get_frame(struct usb_gadget *_gadget)
+{
+       struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+       return (udc_readl(udc, UDCFNR) & 0x7ff);
+}
+
+/**
+ * pxa_udc_wakeup - Force udc device out of suspend
+ * @_gadget: usb gadget
+ *
+ * Returns 0 if succesfull, error code otherwise
+ */
+static int pxa_udc_wakeup(struct usb_gadget *_gadget)
+{
+       struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+       /* host may not have enabled remote wakeup */
+       if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0)
+               return -EHOSTUNREACH;
+       udc_set_mask_UDCCR(udc, UDCCR_UDR);
+       return 0;
+}
+
+static const struct usb_gadget_ops pxa_udc_ops = {
+       .get_frame      = pxa_udc_get_frame,
+       .wakeup         = pxa_udc_wakeup,
+       /* current versions must always be self-powered */
+};
+
+/**
+ * udc_disable - disable udc device controller
+ * @udc: udc device
+ *
+ * Disables the udc device : disables clocks, udc interrupts, control endpoint
+ * interrupts.
+ */
+static void udc_disable(struct pxa_udc *udc)
+{
+       udc_writel(udc, UDCICR0, 0);
+       udc_writel(udc, UDCICR1, 0);
+
+       udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+       clk_disable(udc->clk);
+
+       ep0_idle(udc);
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+}
+
+/**
+ * udc_init_data - Initialize udc device data structures
+ * @dev: udc device
+ *
+ * Initializes gadget endpoint list, endpoints locks. No action is taken
+ * on the hardware.
+ */
+static __init void udc_init_data(struct pxa_udc *dev)
+{
+       int i;
+       struct pxa_ep *ep;
+
+       /* device/ep0 records init */
+       INIT_LIST_HEAD(&dev->gadget.ep_list);
+       INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+       dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0];
+       ep0_idle(dev);
+       strcpy(dev->dev->bus_id, "");
+
+       /* PXA endpoints init */
+       for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+               ep = &dev->pxa_ep[i];
+
+               ep->enabled = is_ep0(ep);
+               INIT_LIST_HEAD(&ep->queue);
+               spin_lock_init(&ep->lock);
+       }
+
+       /* USB endpoints init */
+       for (i = 0; i < NR_USB_ENDPOINTS; i++)
+               if (i != 0)
+                       list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
+                                       &dev->gadget.ep_list);
+}
+
+/**
+ * udc_enable - Enables the udc device
+ * @dev: udc device
+ *
+ * Enables the udc device : enables clocks, udc interrupts, control endpoint
+ * interrupts, sets usb as UDC client and setups endpoints.
+ */
+static void udc_enable(struct pxa_udc *udc)
+{
+       udc_writel(udc, UDCICR0, 0);
+       udc_writel(udc, UDCICR1, 0);
+       udc_writel(udc, UP2OCR, UP2OCR_HXOE);
+       udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+
+       clk_enable(udc->clk);
+
+       ep0_idle(udc);
+       udc->gadget.speed = USB_SPEED_FULL;
+       memset(&udc->stats, 0, sizeof(udc->stats));
+
+       udc_set_mask_UDCCR(udc, UDCCR_UDE);
+       udelay(2);
+       if (udc_readl(udc, UDCCR) & UDCCR_EMCE)
+               dev_err(udc->dev, "Configuration errors, udc disabled\n");
+
+       /*
+        * Caller must be able to sleep in order to cope with startup transients
+        */
+       msleep(100);
+
+       /* enable suspend/resume and reset irqs */
+       udc_writel(udc, UDCICR1,
+                       UDCICR1_IECC | UDCICR1_IERU
+                       | UDCICR1_IESU | UDCICR1_IERS);
+
+       /* enable ep0 irqs */
+       pio_irq_enable(&udc->pxa_ep[0]);
+
+       dev_info(udc->dev, "UDC connecting\n");
+       if (udc->mach->udc_command)
+               udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+}
+
+/**
+ * usb_gadget_register_driver - Register gadget driver
+ * @driver: gadget driver
+ *
+ * When a driver is successfully registered, it will receive control requests
+ * including set_configuration(), which enables non-control requests.  Then
+ * usb traffic follows until a disconnect is reported.  Then a host may connect
+ * again, or the driver might get unbound.
+ *
+ * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct pxa_udc *udc = the_controller;
+       int retval;
+
+       if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind
+                       || !driver->disconnect || !driver->setup)
+               return -EINVAL;
+       if (!udc)
+               return -ENODEV;
+       if (udc->driver)
+               return -EBUSY;
+
+       /* first hook up the driver ... */
+       udc->driver = driver;
+       udc->gadget.dev.driver = &driver->driver;
+
+       retval = device_add(&udc->gadget.dev);
+       if (retval) {
+               dev_err(udc->dev, "device_add error %d\n", retval);
+               goto add_fail;
+       }
+       retval = driver->bind(&udc->gadget);
+       if (retval) {
+               dev_err(udc->dev, "bind to driver %s --> error %d\n",
+                       driver->driver.name, retval);
+               goto bind_fail;
+       }
+       dev_dbg(udc->dev, "registered gadget driver '%s'\n",
+               driver->driver.name);
+
+       udc_enable(udc);
+       return 0;
+
+bind_fail:
+       device_del(&udc->gadget.dev);
+add_fail:
+       udc->driver = NULL;
+       udc->gadget.dev.driver = NULL;
+       return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+
+/**
+ * stop_activity - Stops udc endpoints
+ * @udc: udc device
+ * @driver: gadget driver
+ *
+ * Disables all udc endpoints (even control endpoint), report disconnect to
+ * the gadget user.
+ */
+static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
+{
+       int i;
+
+       /* don't disconnect drivers more than once */
+       if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+               driver = NULL;
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+       for (i = 0; i < NR_USB_ENDPOINTS; i++)
+               pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep);
+
+       if (driver)
+               driver->disconnect(&udc->gadget);
+}
+
+/**
+ * usb_gadget_unregister_driver - Unregister the gadget driver
+ * @driver: gadget driver
+ *
+ * Returns 0 if no error, -ENODEV, -EINVAL otherwise
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct pxa_udc *udc = the_controller;
+
+       if (!udc)
+               return -ENODEV;
+       if (!driver || driver != udc->driver || !driver->unbind)
+               return -EINVAL;
+
+       stop_activity(udc, driver);
+       udc_disable(udc);
+
+       driver->unbind(&udc->gadget);
+       udc->driver = NULL;
+
+       device_del(&udc->gadget.dev);
+
+       dev_info(udc->dev, "unregistered gadget driver '%s'\n",
+                driver->driver.name);
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/**
+ * handle_ep0_ctrl_req - handle control endpoint control request
+ * @udc: udc device
+ * @req: control request
+ */
+static void handle_ep0_ctrl_req(struct pxa_udc *udc,
+                               struct pxa27x_request *req)
+{
+       struct pxa_ep *ep = &udc->pxa_ep[0];
+       union {
+               struct usb_ctrlrequest  r;
+               u32                     word[2];
+       } u;
+       int i;
+       int have_extrabytes = 0;
+
+       nuke(ep, -EPROTO);
+
+       /* read SETUP packet */
+       for (i = 0; i < 2; i++) {
+               if (unlikely(ep_is_empty(ep)))
+                       goto stall;
+               u.word[i] = udc_ep_readl(ep, UDCDR);
+       }
+
+       have_extrabytes = !ep_is_empty(ep);
+       while (!ep_is_empty(ep)) {
+               i = udc_ep_readl(ep, UDCDR);
+               ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i);
+       }
+
+       le16_to_cpus(&u.r.wValue);
+       le16_to_cpus(&u.r.wIndex);
+       le16_to_cpus(&u.r.wLength);
+
+       ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+               u.r.bRequestType, u.r.bRequest,
+               u.r.wValue, u.r.wIndex, u.r.wLength);
+       if (unlikely(have_extrabytes))
+               goto stall;
+
+       if (u.r.bRequestType & USB_DIR_IN)
+               set_ep0state(udc, IN_DATA_STAGE);
+       else
+               set_ep0state(udc, OUT_DATA_STAGE);
+
+       /* Tell UDC to enter Data Stage */
+       udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC);
+
+       i = udc->driver->setup(&udc->gadget, &u.r);
+       if (i < 0)
+               goto stall;
+out:
+       return;
+stall:
+       ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
+               udc_ep_readl(ep, UDCCSR), i);
+       udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF);
+       set_ep0state(udc, STALL);
+       goto out;
+}
+
+/**
+ * handle_ep0 - Handle control endpoint data transfers
+ * @udc: udc device
+ * @fifo_irq: 1 if triggered by fifo service type irq
+ * @opc_irq: 1 if triggered by output packet complete type irq
+ *
+ * Context : when in_interrupt() or with ep->lock held
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ * Handles states of ep0 automata.
+ *
+ * PXA27x hardware handles several standard usb control requests without
+ * driver notification.  The requests fully handled by hardware are :
+ *  SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE,
+ *  GET_STATUS
+ * The requests handled by hardware, but with irq notification are :
+ *  SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE
+ * The remaining standard requests really handled by handle_ep0 are :
+ *  GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests.
+ * Requests standardized outside of USB 2.0 chapter 9 are handled more
+ * uniformly, by gadget drivers.
+ *
+ * The control endpoint state machine is _not_ USB spec compliant, it's even
+ * hardly compliant with Intel PXA270 developers guide.
+ * The key points which inferred this state machine are :
+ *   - on every setup token, bit UDCCSR0_SA is raised and held until cleared by
+ *     software.
+ *   - on every OUT packet received, UDCCSR0_OPC is raised and held until
+ *     cleared by software.
+ *   - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it
+ *     before reading ep0.
+ *   - irq can be called on a "packet complete" event (opc_irq=1), while
+ *     UDCCSR0_OPC is not yet raised (delta can be as big as 100ms
+ *     from experimentation).
+ *   - as UDCCSR0_SA can be activated while in irq handling, and clearing
+ *     UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC
+ *     => we never actually read the "status stage" packet of an IN data stage
+ *     => this is not documented in Intel documentation
+ *   - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA
+ *     STAGE. The driver add STATUS STAGE to send last zero length packet in
+ *     OUT_STATUS_STAGE.
+ *   - special attention was needed for IN_STATUS_STAGE. If a packet complete
+ *     event is detected, we terminate the status stage without ackowledging the
+ *     packet (not to risk to loose a potential SETUP packet)
+ */
+static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
+{
+       u32                     udccsr0;
+       struct pxa_ep           *ep = &udc->pxa_ep[0];
+       struct pxa27x_request   *req = NULL;
+       int                     completed = 0;
+
+       udccsr0 = udc_ep_readl(ep, UDCCSR);
+       ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n",
+               EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR),
+               (fifo_irq << 1 | opc_irq));
+
+       if (!list_empty(&ep->queue))
+               req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+
+       if (udccsr0 & UDCCSR0_SST) {
+               ep_dbg(ep, "clearing stall status\n");
+               nuke(ep, -EPIPE);
+               udc_ep_writel(ep, UDCCSR, UDCCSR0_SST);
+               ep0_idle(udc);
+       }
+
+       if (udccsr0 & UDCCSR0_SA) {
+               nuke(ep, 0);
+               set_ep0state(udc, SETUP_STAGE);
+       }
+
+       switch (udc->ep0state) {
+       case WAIT_FOR_SETUP:
+               /*
+                * Hardware bug : beware, we cannot clear OPC, since we would
+                * miss a potential OPC irq for a setup packet.
+                * So, we only do ... nothing, and hope for a next irq with
+                * UDCCSR0_SA set.
+                */
+               break;
+       case SETUP_STAGE:
+               udccsr0 &= UDCCSR0_CTRL_REQ_MASK;
+               if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK))
+                       handle_ep0_ctrl_req(udc, req);
+               break;
+       case IN_DATA_STAGE:                     /* GET_DESCRIPTOR */
+               if (epout_has_pkt(ep))
+                       udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+               if (req && !ep_is_full(ep))
+                       completed = write_ep0_fifo(ep, req);
+               if (completed)
+                       ep0_end_in_req(ep, req);
+               break;
+       case OUT_DATA_STAGE:                    /* SET_DESCRIPTOR */
+               if (epout_has_pkt(ep) && req)
+                       completed = read_ep0_fifo(ep, req);
+               if (completed)
+                       ep0_end_out_req(ep, req);
+               break;
+       case STALL:
+               udc_ep_writel(ep, UDCCSR, UDCCSR0_FST);
+               break;
+       case IN_STATUS_STAGE:
+               /*
+                * Hardware bug : beware, we cannot clear OPC, since we would
+                * miss a potential PC irq for a setup packet.
+                * So, we only put the ep0 into WAIT_FOR_SETUP state.
+                */
+               if (opc_irq)
+                       ep0_idle(udc);
+               break;
+       case OUT_STATUS_STAGE:
+       case WAIT_ACK_SET_CONF_INTERF:
+               ep_warn(ep, "should never get in %s state here!!!\n",
+                               EP0_STNAME(ep->dev));
+               ep0_idle(udc);
+               break;
+       }
+}
+
+/**
+ * handle_ep - Handle endpoint data tranfers
+ * @ep: pxa physical endpoint
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ *
+ * Is always called when in_interrupt() or with ep->lock held.
+ */
+static void handle_ep(struct pxa_ep *ep)
+{
+       struct pxa27x_request   *req;
+       int completed;
+       u32 udccsr;
+       int is_in = ep->dir_in;
+       int loop = 0;
+
+       do {
+               completed = 0;
+               udccsr = udc_ep_readl(ep, UDCCSR);
+               if (likely(!list_empty(&ep->queue)))
+                       req = list_entry(ep->queue.next,
+                                       struct pxa27x_request, queue);
+               else
+                       req = NULL;
+
+               ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n",
+                               req, udccsr, loop++);
+
+               if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN)))
+                       udc_ep_writel(ep, UDCCSR,
+                                       udccsr & (UDCCSR_SST | UDCCSR_TRN));
+               if (!req)
+                       break;
+
+               if (unlikely(is_in)) {
+                       if (likely(!ep_is_full(ep)))
+                               completed = write_fifo(ep, req);
+                       if (completed)
+                               ep_end_in_req(ep, req);
+               } else {
+                       if (likely(epout_has_pkt(ep)))
+                               completed = read_fifo(ep, req);
+                       if (completed)
+                               ep_end_out_req(ep, req);
+               }
+       } while (completed);
+}
+
+/**
+ * pxa27x_change_configuration - Handle SET_CONF usb request notification
+ * @udc: udc device
+ * @config: usb configuration
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_configuration(struct pxa_udc *udc, int config)
+{
+       struct usb_ctrlrequest req ;
+
+       dev_dbg(udc->dev, "config=%d\n", config);
+
+       udc->config = config;
+       udc->last_interface = 0;
+       udc->last_alternate = 0;
+
+       req.bRequestType = 0;
+       req.bRequest = USB_REQ_SET_CONFIGURATION;
+       req.wValue = config;
+       req.wIndex = 0;
+       req.wLength = 0;
+
+       set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+       udc->driver->setup(&udc->gadget, &req);
+}
+
+/**
+ * pxa27x_change_interface - Handle SET_INTERF usb request notification
+ * @udc: udc device
+ * @iface: interface number
+ * @alt: alternate setting number
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt)
+{
+       struct usb_ctrlrequest  req;
+
+       dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt);
+
+       udc->last_interface = iface;
+       udc->last_alternate = alt;
+
+       req.bRequestType = USB_RECIP_INTERFACE;
+       req.bRequest = USB_REQ_SET_INTERFACE;
+       req.wValue = alt;
+       req.wIndex = iface;
+       req.wLength = 0;
+
+       set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+       udc->driver->setup(&udc->gadget, &req);
+}
+
+/*
+ * irq_handle_data - Handle data transfer
+ * @irq: irq IRQ number
+ * @udc: dev pxa_udc device structure
+ *
+ * Called from irq handler, transferts data to or from endpoint to queue
+ */
+static void irq_handle_data(int irq, struct pxa_udc *udc)
+{
+       int i;
+       struct pxa_ep *ep;
+       u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK;
+       u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK;
+
+       if (udcisr0 & UDCISR_INT_MASK) {
+               udc->pxa_ep[0].stats.irqs++;
+               udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK));
+               handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR),
+                               !!(udcisr0 & UDCICR_PKTCOMPL));
+       }
+
+       udcisr0 >>= 2;
+       for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) {
+               if (!(udcisr0 & UDCISR_INT_MASK))
+                       continue;
+
+               udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
+               ep = &udc->pxa_ep[i];
+               ep->stats.irqs++;
+               handle_ep(ep);
+       }
+
+       for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
+               udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK));
+               if (!(udcisr1 & UDCISR_INT_MASK))
+                       continue;
+
+               ep = &udc->pxa_ep[i];
+               ep->stats.irqs++;
+               handle_ep(ep);
+       }
+
+}
+
+/**
+ * irq_udc_suspend - Handle IRQ "UDC Suspend"
+ * @udc: udc device
+ */
+static void irq_udc_suspend(struct pxa_udc *udc)
+{
+       udc_writel(udc, UDCISR1, UDCISR1_IRSU);
+       udc->stats.irqs_suspend++;
+
+       if (udc->gadget.speed != USB_SPEED_UNKNOWN
+                       && udc->driver && udc->driver->suspend)
+               udc->driver->suspend(&udc->gadget);
+       ep0_idle(udc);
+}
+
+/**
+  * irq_udc_resume - Handle IRQ "UDC Resume"
+  * @udc: udc device
+  */
+static void irq_udc_resume(struct pxa_udc *udc)
+{
+       udc_writel(udc, UDCISR1, UDCISR1_IRRU);
+       udc->stats.irqs_resume++;
+
+       if (udc->gadget.speed != USB_SPEED_UNKNOWN
+                       && udc->driver && udc->driver->resume)
+               udc->driver->resume(&udc->gadget);
+}
+
+/**
+ * irq_udc_reconfig - Handle IRQ "UDC Change Configuration"
+ * @udc: udc device
+ */
+static void irq_udc_reconfig(struct pxa_udc *udc)
+{
+       unsigned config, interface, alternate, config_change;
+       u32 udccr = udc_readl(udc, UDCCR);
+
+       udc_writel(udc, UDCISR1, UDCISR1_IRCC);
+       udc->stats.irqs_reconfig++;
+
+       config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S;
+       config_change = (config != udc->config);
+       pxa27x_change_configuration(udc, config);
+
+       interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S;
+       alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S;
+       pxa27x_change_interface(udc, interface, alternate);
+
+       if (config_change)
+               update_pxa_ep_matches(udc);
+       udc_set_mask_UDCCR(udc, UDCCR_SMAC);
+}
+
+/**
+ * irq_udc_reset - Handle IRQ "UDC Reset"
+ * @udc: udc device
+ */
+static void irq_udc_reset(struct pxa_udc *udc)
+{
+       u32 udccr = udc_readl(udc, UDCCR);
+       struct pxa_ep *ep = &udc->pxa_ep[0];
+
+       dev_info(udc->dev, "USB reset\n");
+       udc_writel(udc, UDCISR1, UDCISR1_IRRS);
+       udc->stats.irqs_reset++;
+
+       if ((udccr & UDCCR_UDA) == 0) {
+               dev_dbg(udc->dev, "USB reset start\n");
+               stop_activity(udc, udc->driver);
+       }
+       udc->gadget.speed = USB_SPEED_FULL;
+       memset(&udc->stats, 0, sizeof udc->stats);
+
+       nuke(ep, -EPROTO);
+       udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC);
+       ep0_idle(udc);
+}
+
+/**
+ * pxa_udc_irq - Main irq handler
+ * @irq: irq number
+ * @_dev: udc device
+ *
+ * Handles all udc interrupts
+ */
+static irqreturn_t pxa_udc_irq(int irq, void *_dev)
+{
+       struct pxa_udc *udc = _dev;
+       u32 udcisr0 = udc_readl(udc, UDCISR0);
+       u32 udcisr1 = udc_readl(udc, UDCISR1);
+       u32 udccr = udc_readl(udc, UDCCR);
+       u32 udcisr1_spec;
+
+       dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, "
+                "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr);
+
+       udcisr1_spec = udcisr1 & 0xf8000000;
+       if (unlikely(udcisr1_spec & UDCISR1_IRSU))
+               irq_udc_suspend(udc);
+       if (unlikely(udcisr1_spec & UDCISR1_IRRU))
+               irq_udc_resume(udc);
+       if (unlikely(udcisr1_spec & UDCISR1_IRCC))
+               irq_udc_reconfig(udc);
+       if (unlikely(udcisr1_spec & UDCISR1_IRRS))
+               irq_udc_reset(udc);
+
+       if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK))
+               irq_handle_data(irq, udc);
+
+       return IRQ_HANDLED;
+}
+
+static struct pxa_udc memory = {
+       .gadget = {
+               .ops            = &pxa_udc_ops,
+               .ep0            = &memory.udc_usb_ep[0].usb_ep,
+               .name           = driver_name,
+               .dev = {
+                       .bus_id         = "gadget",
+               },
+       },
+
+       .udc_usb_ep = {
+               USB_EP_CTRL,
+               USB_EP_OUT_BULK(1),
+               USB_EP_IN_BULK(2),
+               USB_EP_IN_ISO(3),
+               USB_EP_OUT_ISO(4),
+               USB_EP_IN_INT(5),
+       },
+
+       .pxa_ep = {
+               PXA_EP_CTRL,
+               /* Endpoints for gadget zero */
+               PXA_EP_OUT_BULK(1, 1, 3, 0, 0),
+               PXA_EP_IN_BULK(2,  2, 3, 0, 0),
+               /* Endpoints for ether gadget, file storage gadget */
+               PXA_EP_OUT_BULK(3, 1, 1, 0, 0),
+               PXA_EP_IN_BULK(4,  2, 1, 0, 0),
+               PXA_EP_IN_ISO(5,   3, 1, 0, 0),
+               PXA_EP_OUT_ISO(6,  4, 1, 0, 0),
+               PXA_EP_IN_INT(7,   5, 1, 0, 0),
+               /* Endpoints for RNDIS, serial */
+               PXA_EP_OUT_BULK(8, 1, 2, 0, 0),
+               PXA_EP_IN_BULK(9,  2, 2, 0, 0),
+               PXA_EP_IN_INT(10,  5, 2, 0, 0),
+               /*
+                * All the following endpoints are only for completion.  They
+                * won't never work, as multiple interfaces are really broken on
+                * the pxa.
+               */
+               PXA_EP_OUT_BULK(11, 1, 2, 1, 0),
+               PXA_EP_IN_BULK(12,  2, 2, 1, 0),
+               /* Endpoint for CDC Ether */
+               PXA_EP_OUT_BULK(13, 1, 1, 1, 1),
+               PXA_EP_IN_BULK(14,  2, 1, 1, 1),
+       }
+};
+
+/**
+ * pxa_udc_probe - probes the udc device
+ * @_dev: platform device
+ *
+ * Perform basic init : allocates udc clock, creates sysfs files, requests
+ * irq.
+ */
+static int __init pxa_udc_probe(struct platform_device *pdev)
+{
+       struct resource *regs;
+       struct pxa_udc *udc = &memory;
+       int retval;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs)
+               return -ENXIO;
+       udc->irq = platform_get_irq(pdev, 0);
+       if (udc->irq < 0)
+               return udc->irq;
+
+       udc->dev = &pdev->dev;
+       udc->mach = pdev->dev.platform_data;
+
+       udc->clk = clk_get(&pdev->dev, "UDCCLK");
+       if (IS_ERR(udc->clk)) {
+               retval = PTR_ERR(udc->clk);
+               goto err_clk;
+       }
+
+       retval = -ENOMEM;
+       udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       if (!udc->regs) {
+               dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
+               goto err_map;
+       }
+
+       device_initialize(&udc->gadget.dev);
+       udc->gadget.dev.parent = &pdev->dev;
+       udc->gadget.dev.dma_mask = NULL;
+
+       the_controller = udc;
+       platform_set_drvdata(pdev, udc);
+       udc_init_data(udc);
+       pxa_eps_setup(udc);
+
+       /* irq setup after old hardware state is cleaned up */
+       retval = request_irq(udc->irq, pxa_udc_irq,
+                       IRQF_SHARED, driver_name, udc);
+       if (retval != 0) {
+               dev_err(udc->dev, "%s: can't get irq %i, err %d\n",
+                       driver_name, IRQ_USB, retval);
+               goto err_irq;
+       }
+
+       pxa_init_debugfs(udc);
+       return 0;
+err_irq:
+       iounmap(udc->regs);
+err_map:
+       clk_put(udc->clk);
+       udc->clk = NULL;
+err_clk:
+       return retval;
+}
+
+/**
+ * pxa_udc_remove - removes the udc device driver
+ * @_dev: platform device
+ */
+static int __exit pxa_udc_remove(struct platform_device *_dev)
+{
+       struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+       usb_gadget_unregister_driver(udc->driver);
+       free_irq(udc->irq, udc);
+       pxa_cleanup_debugfs(udc);
+
+       platform_set_drvdata(_dev, NULL);
+       the_controller = NULL;
+       clk_put(udc->clk);
+
+       return 0;
+}
+
+static void pxa_udc_shutdown(struct platform_device *_dev)
+{
+       struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+       udc_disable(udc);
+}
+
+#ifdef CONFIG_PM
+/**
+ * pxa_udc_suspend - Suspend udc device
+ * @_dev: platform device
+ * @state: suspend state
+ *
+ * Suspends udc : saves configuration registers (UDCCR*), then disables the udc
+ * device.
+ */
+static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
+{
+       int i;
+       struct pxa_udc *udc = platform_get_drvdata(_dev);
+       struct pxa_ep *ep;
+
+       ep = &udc->pxa_ep[0];
+       udc->udccsr0 = udc_ep_readl(ep, UDCCSR);
+       for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+               ep = &udc->pxa_ep[i];
+               ep->udccsr_value = udc_ep_readl(ep, UDCCSR);
+               ep->udccr_value  = udc_ep_readl(ep, UDCCR);
+               ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+                               ep->udccsr_value, ep->udccr_value);
+       }
+
+       udc_disable(udc);
+
+       return 0;
+}
+
+/**
+ * pxa_udc_resume - Resume udc device
+ * @_dev: platform device
+ *
+ * Resumes udc : restores configuration registers (UDCCR*), then enables the udc
+ * device.
+ */
+static int pxa_udc_resume(struct platform_device *_dev)
+{
+       int i;
+       struct pxa_udc *udc = platform_get_drvdata(_dev);
+       struct pxa_ep *ep;
+
+       ep = &udc->pxa_ep[0];
+       udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME));
+       for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+               ep = &udc->pxa_ep[i];
+               udc_ep_writel(ep, UDCCSR, ep->udccsr_value);
+               udc_ep_writel(ep, UDCCR,  ep->udccr_value);
+               ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+                               ep->udccsr_value, ep->udccr_value);
+       }
+
+       udc_enable(udc);
+       /*
+        * We do not handle OTG yet.
+        *
+        * OTGPH bit is set when sleep mode is entered.
+        * it indicates that OTG pad is retaining its state.
+        * Upon exit from sleep mode and before clearing OTGPH,
+        * Software must configure the USB OTG pad, UDC, and UHC
+        * to the state they were in before entering sleep mode.
+        *
+        * Should be : PSSR |= PSSR_OTGPH;
+        */
+
+       return 0;
+}
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:pxa2xx-udc");
+
+static struct platform_driver udc_driver = {
+       .driver         = {
+               .name   = "pxa2xx-udc",
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __exit_p(pxa_udc_remove),
+       .shutdown       = pxa_udc_shutdown,
+#ifdef CONFIG_PM
+       .suspend        = pxa_udc_suspend,
+       .resume         = pxa_udc_resume
+#endif
+};
+
+static int __init udc_init(void)
+{
+       printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
+       return platform_driver_probe(&udc_driver, pxa_udc_probe);
+}
+module_init(udc_init);
+
+
+static void __exit udc_exit(void)
+{
+       platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
new file mode 100644 (file)
index 0000000..1d1b793
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * linux/drivers/usb/gadget/pxa27x_udc.h
+ * Intel PXA27x on-chip full speed USB device controller
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307         USA
+ */
+
+#ifndef __LINUX_USB_GADGET_PXA27X_H
+#define __LINUX_USB_GADGET_PXA27X_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+/*
+ * Register definitions
+ */
+/* Offsets */
+#define UDCCR          0x0000          /* UDC Control Register */
+#define UDCICR0                0x0004          /* UDC Interrupt Control Register0 */
+#define UDCICR1                0x0008          /* UDC Interrupt Control Register1 */
+#define UDCISR0                0x000C          /* UDC Interrupt Status Register 0 */
+#define UDCISR1                0x0010          /* UDC Interrupt Status Register 1 */
+#define UDCFNR         0x0014          /* UDC Frame Number Register */
+#define UDCOTGICR      0x0018          /* UDC On-The-Go interrupt control */
+#define UP2OCR         0x0020          /* USB Port 2 Output Control register */
+#define UP3OCR         0x0024          /* USB Port 3 Output Control register */
+#define UDCCSRn(x)     (0x0100 + ((x)<<2)) /* UDC Control/Status register */
+#define UDCBCRn(x)     (0x0200 + ((x)<<2)) /* UDC Byte Count Register */
+#define UDCDRn(x)      (0x0300 + ((x)<<2)) /* UDC Data Register  */
+#define UDCCRn(x)      (0x0400 + ((x)<<2)) /* UDC Control Register */
+
+#define UDCCR_OEN      (1 << 31)       /* On-the-Go Enable */
+#define UDCCR_AALTHNP  (1 << 30)       /* A-device Alternate Host Negotiation
+                                          Protocol Port Support */
+#define UDCCR_AHNP     (1 << 29)       /* A-device Host Negotiation Protocol
+                                          Support */
+#define UDCCR_BHNP     (1 << 28)       /* B-device Host Negotiation Protocol
+                                          Enable */
+#define UDCCR_DWRE     (1 << 16)       /* Device Remote Wake-up Enable */
+#define UDCCR_ACN      (0x03 << 11)    /* Active UDC configuration Number */
+#define UDCCR_ACN_S    11
+#define UDCCR_AIN      (0x07 << 8)     /* Active UDC interface Number */
+#define UDCCR_AIN_S    8
+#define UDCCR_AAISN    (0x07 << 5)     /* Active UDC Alternate Interface
+                                          Setting Number */
+#define UDCCR_AAISN_S  5
+#define UDCCR_SMAC     (1 << 4)        /* Switch Endpoint Memory to Active
+                                          Configuration */
+#define UDCCR_EMCE     (1 << 3)        /* Endpoint Memory Configuration
+                                          Error */
+#define UDCCR_UDR      (1 << 2)        /* UDC Resume */
+#define UDCCR_UDA      (1 << 1)        /* UDC Active */
+#define UDCCR_UDE      (1 << 0)        /* UDC Enable */
+
+#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCICR1_IECC   (1 << 31)       /* IntEn - Configuration Change */
+#define UDCICR1_IESOF  (1 << 30)       /* IntEn - Start of Frame */
+#define UDCICR1_IERU   (1 << 29)       /* IntEn - Resume */
+#define UDCICR1_IESU   (1 << 28)       /* IntEn - Suspend */
+#define UDCICR1_IERS   (1 << 27)       /* IntEn - Reset */
+#define UDCICR_FIFOERR (1 << 1)        /* FIFO Error interrupt for EP */
+#define UDCICR_PKTCOMPL        (1 << 0)        /* Packet Complete interrupt for EP */
+#define UDCICR_INT_MASK        (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCISR1_IRCC   (1 << 31)       /* IntReq - Configuration Change */
+#define UDCISR1_IRSOF  (1 << 30)       /* IntReq - Start of Frame */
+#define UDCISR1_IRRU   (1 << 29)       /* IntReq - Resume */
+#define UDCISR1_IRSU   (1 << 28)       /* IntReq - Suspend */
+#define UDCISR1_IRRS   (1 << 27)       /* IntReq - Reset */
+#define UDCISR_INT_MASK        (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCOTGICR_IESF (1 << 24)       /* OTG SET_FEATURE command recvd */
+#define UDCOTGICR_IEXR (1 << 17)       /* Extra Transciever Interrupt
+                                          Rising Edge Interrupt Enable */
+#define UDCOTGICR_IEXF (1 << 16)       /* Extra Transciever Interrupt
+                                          Falling Edge Interrupt Enable */
+#define UDCOTGICR_IEVV40R (1 << 9)     /* OTG Vbus Valid 4.0V Rising Edge
+                                          Interrupt Enable */
+#define UDCOTGICR_IEVV40F (1 << 8)     /* OTG Vbus Valid 4.0V Falling Edge
+                                          Interrupt Enable */
+#define UDCOTGICR_IEVV44R (1 << 7)     /* OTG Vbus Valid 4.4V Rising Edge
+                                          Interrupt Enable */
+#define UDCOTGICR_IEVV44F (1 << 6)     /* OTG Vbus Valid 4.4V Falling Edge
+                                          Interrupt Enable */
+#define UDCOTGICR_IESVR        (1 << 5)        /* OTG Session Valid Rising Edge
+                                          Interrupt Enable */
+#define UDCOTGICR_IESVF        (1 << 4)        /* OTG Session Valid Falling Edge
+                                          Interrupt Enable */
+#define UDCOTGICR_IESDR        (1 << 3)        /* OTG A-Device SRP Detect Rising
+                                          Edge Interrupt Enable */
+#define UDCOTGICR_IESDF        (1 << 2)        /* OTG A-Device SRP Detect Falling
+                                          Edge Interrupt Enable */
+#define UDCOTGICR_IEIDR        (1 << 1)        /* OTG ID Change Rising Edge
+                                          Interrupt Enable */
+#define UDCOTGICR_IEIDF        (1 << 0)        /* OTG ID Change Falling Edge
+                                          Interrupt Enable */
+
+/* Host Port 2 field bits */
+#define UP2OCR_CPVEN   (1 << 0)        /* Charge Pump Vbus Enable */
+#define UP2OCR_CPVPE   (1 << 1)        /* Charge Pump Vbus Pulse Enable */
+                                       /* Transceiver enablers */
+#define UP2OCR_DPPDE   (1 << 2)        /*   D+ Pull Down Enable */
+#define UP2OCR_DMPDE   (1 << 3)        /*   D- Pull Down Enable */
+#define UP2OCR_DPPUE   (1 << 4)        /*   D+ Pull Up Enable */
+#define UP2OCR_DMPUE   (1 << 5)        /*   D- Pull Up Enable */
+#define UP2OCR_DPPUBE  (1 << 6)        /*   D+ Pull Up Bypass Enable */
+#define UP2OCR_DMPUBE  (1 << 7)        /*   D- Pull Up Bypass Enable */
+#define UP2OCR_EXSP    (1 << 8)        /* External Transceiver Speed Control */
+#define UP2OCR_EXSUS   (1 << 9)        /* External Transceiver Speed Enable */
+#define UP2OCR_IDON    (1 << 10)       /* OTG ID Read Enable */
+#define UP2OCR_HXS     (1 << 16)       /* Transceiver Output Select */
+#define UP2OCR_HXOE    (1 << 17)       /* Transceiver Output Enable */
+#define UP2OCR_SEOS    (1 << 24)       /* Single-Ended Output Select */
+
+#define UDCCSR0_SA     (1 << 7)        /* Setup Active */
+#define UDCCSR0_RNE    (1 << 6)        /* Receive FIFO Not Empty */
+#define UDCCSR0_FST    (1 << 5)        /* Force Stall */
+#define UDCCSR0_SST    (1 << 4)        /* Sent Stall */
+#define UDCCSR0_DME    (1 << 3)        /* DMA Enable */
+#define UDCCSR0_FTF    (1 << 2)        /* Flush Transmit FIFO */
+#define UDCCSR0_IPR    (1 << 1)        /* IN Packet Ready */
+#define UDCCSR0_OPC    (1 << 0)        /* OUT Packet Complete */
+
+#define UDCCSR_DPE     (1 << 9)        /* Data Packet Error */
+#define UDCCSR_FEF     (1 << 8)        /* Flush Endpoint FIFO */
+#define UDCCSR_SP      (1 << 7)        /* Short Packet Control/Status */
+#define UDCCSR_BNE     (1 << 6)        /* Buffer Not Empty (IN endpoints) */
+#define UDCCSR_BNF     (1 << 6)        /* Buffer Not Full (OUT endpoints) */
+#define UDCCSR_FST     (1 << 5)        /* Force STALL */
+#define UDCCSR_SST     (1 << 4)        /* Sent STALL */
+#define UDCCSR_DME     (1 << 3)        /* DMA Enable */
+#define UDCCSR_TRN     (1 << 2)        /* Tx/Rx NAK */
+#define UDCCSR_PC      (1 << 1)        /* Packet Complete */
+#define UDCCSR_FS      (1 << 0)        /* FIFO needs service */
+
+#define UDCCONR_CN     (0x03 << 25)    /* Configuration Number */
+#define UDCCONR_CN_S   25
+#define UDCCONR_IN     (0x07 << 22)    /* Interface Number */
+#define UDCCONR_IN_S   22
+#define UDCCONR_AISN   (0x07 << 19)    /* Alternate Interface Number */
+#define UDCCONR_AISN_S 19
+#define UDCCONR_EN     (0x0f << 15)    /* Endpoint Number */
+#define UDCCONR_EN_S   15
+#define UDCCONR_ET     (0x03 << 13)    /* Endpoint Type: */
+#define UDCCONR_ET_S   13
+#define UDCCONR_ET_INT (0x03 << 13)    /*   Interrupt */
+#define UDCCONR_ET_BULK        (0x02 << 13)    /*   Bulk */
+#define UDCCONR_ET_ISO (0x01 << 13)    /*   Isochronous */
+#define UDCCONR_ET_NU  (0x00 << 13)    /*   Not used */
+#define UDCCONR_ED     (1 << 12)       /* Endpoint Direction */
+#define UDCCONR_MPS    (0x3ff << 2)    /* Maximum Packet Size */
+#define UDCCONR_MPS_S  2
+#define UDCCONR_DE     (1 << 1)        /* Double Buffering Enable */
+#define UDCCONR_EE     (1 << 0)        /* Endpoint Enable */
+
+#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_SMAC | UDCCR_UDR | UDCCR_UDE)
+#define UDCCSR_WR_MASK (UDCCSR_DME | UDCCSR_FST)
+#define UDC_FNR_MASK   (0x7ff)
+#define UDC_BCR_MASK   (0x3ff)
+
+/*
+ * UDCCR = UDC Endpoint Configuration Registers
+ * UDCCSR = UDC Control/Status Register for this EP
+ * UDCBCR = UDC Byte Count Remaining (contents of OUT fifo)
+ * UDCDR = UDC Endpoint Data Register (the fifo)
+ */
+#define ofs_UDCCR(ep)  (UDCCRn(ep->idx))
+#define ofs_UDCCSR(ep) (UDCCSRn(ep->idx))
+#define ofs_UDCBCR(ep) (UDCBCRn(ep->idx))
+#define ofs_UDCDR(ep)  (UDCDRn(ep->idx))
+
+/* Register access macros */
+#define udc_ep_readl(ep, reg)  \
+       __raw_readl((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writel(ep, reg, value)  \
+       __raw_writel((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_ep_readb(ep, reg)  \
+       __raw_readb((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writeb(ep, reg, value)  \
+       __raw_writeb((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_readl(dev, reg)    \
+       __raw_readl((dev)->regs + (reg))
+#define udc_writel(udc, reg, value)    \
+       __raw_writel((value), (udc)->regs + (reg))
+
+#define UDCCSR_MASK            (UDCCSR_FST | UDCCSR_DME)
+#define UDCCISR0_EP_MASK       ~0
+#define UDCCISR1_EP_MASK       0xffff
+#define UDCCSR0_CTRL_REQ_MASK  (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)
+
+#define EPIDX(ep)      (ep->idx)
+#define EPADDR(ep)     (ep->addr)
+#define EPXFERTYPE(ep) (ep->type)
+#define EPNAME(ep)     (ep->name)
+#define is_ep0(ep)     (!ep->idx)
+#define EPXFERTYPE_is_ISO(ep) (EPXFERTYPE(ep) == USB_ENDPOINT_XFER_ISOC)
+
+/*
+ * Endpoint definitions
+ *
+ * Once enabled, pxa endpoint configuration is freezed, and cannot change
+ * unless a reset happens or the udc is disabled.
+ * Therefore, we must define all pxa potential endpoint definitions needed for
+ * all gadget and set them up before the udc is enabled.
+ *
+ * As the architecture chosen is fully static, meaning the pxa endpoint
+ * configurations are set up once and for all, we must provide a way to match
+ * one usb endpoint (usb_ep) to several pxa endpoints. The reason is that gadget
+ * layer autoconf doesn't choose the usb_ep endpoint on (config, interface, alt)
+ * criteria, while the pxa architecture requires that.
+ *
+ * The solution is to define several pxa endpoints matching one usb_ep. Ex:
+ *   - "ep1-in" matches pxa endpoint EPA (which is an IN ep at addr 1, when
+ *     the udc talks on (config=3, interface=0, alt=0)
+ *   - "ep1-in" matches pxa endpoint EPB (which is an IN ep at addr 1, when
+ *     the udc talks on (config=3, interface=0, alt=1)
+ *   - "ep1-in" matches pxa endpoint EPC (which is an IN ep at addr 1, when
+ *     the udc talks on (config=2, interface=0, alt=0)
+ *
+ * We'll define the pxa endpoint by its index (EPA => idx=1, EPB => idx=2, ...)
+ */
+
+/*
+ * Endpoint definition helpers
+ */
+#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \
+{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \
+  .desc = {    .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \
+               .bmAttributes = type, \
+               .wMaxPacketSize = maxpkt, }, \
+  .dev = &memory \
+}
+#define USB_EP_BULK(addr, bname, dir) \
+  USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE)
+#define USB_EP_ISO(addr, bname, dir) \
+  USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE)
+#define USB_EP_INT(addr, bname, dir) \
+  USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE)
+#define USB_EP_IN_BULK(n)      USB_EP_BULK(n, "ep" #n "in-bulk", 1)
+#define USB_EP_OUT_BULK(n)     USB_EP_BULK(n, "ep" #n "out-bulk", 0)
+#define USB_EP_IN_ISO(n)       USB_EP_ISO(n,  "ep" #n "in-iso", 1)
+#define USB_EP_OUT_ISO(n)      USB_EP_ISO(n,  "ep" #n "out-iso", 0)
+#define USB_EP_IN_INT(n)       USB_EP_INT(n,  "ep" #n "in-int", 1)
+#define USB_EP_CTRL            USB_EP_DEF(0,  "ep0", 0, 0, EP0_FIFO_SIZE)
+
+#define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \
+{ \
+       .dev = &memory, \
+       .name = "ep" #_idx, \
+       .idx = _idx, .enabled = 0, \
+       .dir_in = dir, .addr = _addr, \
+       .config = _config, .interface = iface, .alternate = altset, \
+       .type = _type, .fifo_size = maxpkt, \
+}
+#define PXA_EP_BULK(_idx, addr, dir, config, iface, alt) \
+  PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE, \
+               config, iface, alt)
+#define PXA_EP_ISO(_idx, addr, dir, config, iface, alt) \
+  PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE, \
+               config, iface, alt)
+#define PXA_EP_INT(_idx, addr, dir, config, iface, alt) \
+  PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE, \
+               config, iface, alt)
+#define PXA_EP_IN_BULK(i, adr, c, f, a)                PXA_EP_BULK(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_BULK(i, adr, c, f, a)       PXA_EP_BULK(i, adr, 0, c, f, a)
+#define PXA_EP_IN_ISO(i, adr, c, f, a)         PXA_EP_ISO(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_ISO(i, adr, c, f, a)                PXA_EP_ISO(i, adr, 0, c, f, a)
+#define PXA_EP_IN_INT(i, adr, c, f, a)         PXA_EP_INT(i, adr, 1, c, f, a)
+#define PXA_EP_CTRL    PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0)
+
+struct pxa27x_udc;
+
+struct stats {
+       unsigned long in_ops;
+       unsigned long out_ops;
+       unsigned long in_bytes;
+       unsigned long out_bytes;
+       unsigned long irqs;
+};
+
+/**
+ * struct udc_usb_ep - container of each usb_ep structure
+ * @usb_ep: usb endpoint
+ * @desc: usb descriptor, especially type and address
+ * @dev: udc managing this endpoint
+ * @pxa_ep: matching pxa_ep (cache of find_pxa_ep() call)
+ */
+struct udc_usb_ep {
+       struct usb_ep usb_ep;
+       struct usb_endpoint_descriptor desc;
+       struct pxa_udc *dev;
+       struct pxa_ep *pxa_ep;
+};
+
+/**
+ * struct pxa_ep - pxa endpoint
+ * @dev: udc device
+ * @queue: requests queue
+ * @lock: lock to pxa_ep data (queues and stats)
+ * @enabled: true when endpoint enabled (not stopped by gadget layer)
+ * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
+ * @name: endpoint name (for trace/debug purpose)
+ * @dir_in: 1 if IN endpoint, 0 if OUT endpoint
+ * @addr: usb endpoint number
+ * @config: configuration in which this endpoint is active
+ * @interface: interface in which this endpoint is active
+ * @alternate: altsetting in which this endpoitn is active
+ * @fifo_size: max packet size in the endpoint fifo
+ * @type: endpoint type (bulk, iso, int, ...)
+ * @udccsr_value: save register of UDCCSR0 for suspend/resume
+ * @udccr_value: save register of UDCCR for suspend/resume
+ * @stats: endpoint statistics
+ *
+ * The *PROBLEM* is that pxa's endpoint configuration scheme is both misdesigned
+ * (cares about config/interface/altsetting, thus placing needless limits on
+ * device capability) and full of implementation bugs forcing it to be set up
+ * for use more or less like a pxa255.
+ *
+ * As we define the pxa_ep statically, we must guess all needed pxa_ep for all
+ * gadget which may work with this udc driver.
+ */
+struct pxa_ep {
+       struct pxa_udc          *dev;
+
+       struct list_head        queue;
+       spinlock_t              lock;           /* Protects this structure */
+                                               /* (queues, stats) */
+       unsigned                enabled:1;
+
+       unsigned                idx:5;
+       char                    *name;
+
+       /*
+        * Specific pxa endpoint data, needed for hardware initialization
+        */
+       unsigned                dir_in:1;
+       unsigned                addr:3;
+       unsigned                config:2;
+       unsigned                interface:3;
+       unsigned                alternate:3;
+       unsigned                fifo_size;
+       unsigned                type;
+
+#ifdef CONFIG_PM
+       u32                     udccsr_value;
+       u32                     udccr_value;
+#endif
+       struct stats            stats;
+};
+
+/**
+ * struct pxa27x_request - container of each usb_request structure
+ * @req: usb request
+ * @udc_usb_ep: usb endpoint the request was submitted on
+ * @in_use: sanity check if request already queued on an pxa_ep
+ * @queue: linked list of requests, linked on pxa_ep->queue
+ */
+struct pxa27x_request {
+       struct usb_request                      req;
+       struct udc_usb_ep                       *udc_usb_ep;
+       unsigned                                in_use:1;
+       struct list_head                        queue;
+};
+
+enum ep0_state {
+       WAIT_FOR_SETUP,
+       SETUP_STAGE,
+       IN_DATA_STAGE,
+       OUT_DATA_STAGE,
+       IN_STATUS_STAGE,
+       OUT_STATUS_STAGE,
+       STALL,
+       WAIT_ACK_SET_CONF_INTERF
+};
+
+static char *ep0_state_name[] = {
+       "WAIT_FOR_SETUP", "SETUP_STAGE", "IN_DATA_STAGE", "OUT_DATA_STAGE",
+       "IN_STATUS_STAGE", "OUT_STATUS_STAGE", "STALL",
+       "WAIT_ACK_SET_CONF_INTERF"
+};
+#define EP0_STNAME(udc) ep0_state_name[(udc)->ep0state]
+
+#define EP0_FIFO_SIZE  16U
+#define BULK_FIFO_SIZE 64U
+#define ISO_FIFO_SIZE  256U
+#define INT_FIFO_SIZE  16U
+
+struct udc_stats {
+       unsigned long   irqs_reset;
+       unsigned long   irqs_suspend;
+       unsigned long   irqs_resume;
+       unsigned long   irqs_reconfig;
+};
+
+#define NR_USB_ENDPOINTS (1 + 5)       /* ep0 + ep1in-bulk + .. + ep3in-iso */
+#define NR_PXA_ENDPOINTS (1 + 14)      /* ep0 + epA + epB + .. + epX */
+
+/**
+ * struct pxa_udc - udc structure
+ * @regs: mapped IO space
+ * @irq: udc irq
+ * @clk: udc clock
+ * @usb_gadget: udc gadget structure
+ * @driver: bound gadget (zero, g_ether, g_file_storage, ...)
+ * @dev: device
+ * @mach: machine info, used to activate specific GPIO
+ * @ep0state: control endpoint state machine state
+ * @stats: statistics on udc usage
+ * @udc_usb_ep: array of usb endpoints offered by the gadget
+ * @pxa_ep: array of pxa available endpoints
+ * @config: UDC active configuration
+ * @last_interface: UDC interface of the last SET_INTERFACE host request
+ * @last_alternate: UDC altsetting of the last SET_INTERFACE host request
+ * @udccsr0: save of udccsr0 in case of suspend
+ * @debugfs_root: root entry of debug filesystem
+ * @debugfs_state: debugfs entry for "udcstate"
+ * @debugfs_queues: debugfs entry for "queues"
+ * @debugfs_eps: debugfs entry for "epstate"
+ */
+struct pxa_udc {
+       void __iomem                            *regs;
+       int                                     irq;
+       struct clk                              *clk;
+
+       struct usb_gadget                       gadget;
+       struct usb_gadget_driver                *driver;
+       struct device                           *dev;
+       struct pxa2xx_udc_mach_info             *mach;
+
+       enum ep0_state                          ep0state;
+       struct udc_stats                        stats;
+
+       struct udc_usb_ep                       udc_usb_ep[NR_USB_ENDPOINTS];
+       struct pxa_ep                           pxa_ep[NR_PXA_ENDPOINTS];
+
+       unsigned                                config:2;
+       unsigned                                last_interface:3;
+       unsigned                                last_alternate:3;
+
+#ifdef CONFIG_PM
+       unsigned                                udccsr0;
+#endif
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       struct dentry                           *debugfs_root;
+       struct dentry                           *debugfs_state;
+       struct dentry                           *debugfs_queues;
+       struct dentry                           *debugfs_eps;
+#endif
+};
+
+static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
+{
+       return container_of(gadget, struct pxa_udc, gadget);
+}
+
+/*
+ * Debugging/message support
+ */
+#define ep_dbg(ep, fmt, arg...) \
+       dev_dbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_vdbg(ep, fmt, arg...) \
+       dev_vdbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_err(ep, fmt, arg...) \
+       dev_err(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_info(ep, fmt, arg...) \
+       dev_info(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_warn(ep, fmt, arg...) \
+       dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg)
+
+#endif /* __LINUX_USB_GADGET_PXA27X_H */
index 8d158e5640e37782ea0dbed21c08277092a2614e..54cdd6f940346732fe38379ad75cd542a66e5709 100644 (file)
@@ -135,7 +135,10 @@ struct gs_port {
        int                     port_in_use;    /* open/close in progress */
        wait_queue_head_t       port_write_wait;/* waiting to write */
        struct gs_buf           *port_write_buf;
-       struct usb_cdc_line_coding      port_line_coding;
+       struct usb_cdc_line_coding port_line_coding;    /* 8-N-1 etc */
+       u16                     port_handshake_bits;
+#define RS232_RTS      (1 << 1)
+#define RS232_DTE      (1 << 0)
 };
 
 /* the device structure holds info for the USB device */
@@ -199,6 +202,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
 static int gs_setup_class(struct usb_gadget *gadget,
        const struct usb_ctrlrequest *ctrl);
 static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+       struct usb_request *req);
 static void gs_disconnect(struct usb_gadget *gadget);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
@@ -406,7 +411,7 @@ static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
        .bLength =              sizeof(gs_acm_descriptor),
        .bDescriptorType =      USB_DT_CS_INTERFACE,
        .bDescriptorSubType =   USB_CDC_ACM_TYPE,
-       .bmCapabilities =       0,
+       .bmCapabilities =       (1 << 1),
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
@@ -1502,6 +1507,8 @@ static int gs_setup(struct usb_gadget *gadget,
        u16 wValue = le16_to_cpu(ctrl->wValue);
        u16 wLength = le16_to_cpu(ctrl->wLength);
 
+       req->complete = gs_setup_complete;
+
        switch (ctrl->bRequestType & USB_TYPE_MASK) {
        case USB_TYPE_STANDARD:
                ret = gs_setup_standard(gadget,ctrl);
@@ -1679,18 +1686,14 @@ static int gs_setup_class(struct usb_gadget *gadget,
 
        switch (ctrl->bRequest) {
        case USB_CDC_REQ_SET_LINE_CODING:
-               /* FIXME Submit req to read the data; have its completion
-                * handler copy that data to port->port_line_coding (iff
-                * it's valid) and maybe pass it on.  Until then, fail.
-                */
-               pr_warning("gs_setup: set_line_coding "
-                               "unuspported\n");
+               if (wLength != sizeof(struct usb_cdc_line_coding))
+                       break;
+               ret = wLength;
+               req->complete = gs_setup_complete_set_line_coding;
                break;
 
        case USB_CDC_REQ_GET_LINE_CODING:
-               port = dev->dev_port[0];        /* ACM only has one port */
-               ret = min(wLength,
-                       (u16)sizeof(struct usb_cdc_line_coding));
+               ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
                if (port) {
                        spin_lock(&port->port_lock);
                        memcpy(req->buf, &port->port_line_coding, ret);
@@ -1699,15 +1702,27 @@ static int gs_setup_class(struct usb_gadget *gadget,
                break;
 
        case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
-               /* FIXME Submit req to read the data; have its completion
-                * handler use that to set the state (iff it's valid) and
-                * maybe pass it on.  Until then, fail.
-                */
-               pr_warning("gs_setup: set_control_line_state "
-                               "unuspported\n");
+               if (wLength != 0)
+                       break;
+               ret = 0;
+               if (port) {
+                       /* REVISIT:  we currently just remember this data.
+                        * If we change that, update whatever hardware needs
+                        * updating.
+                        */
+                       spin_lock(&port->port_lock);
+                       port->port_handshake_bits = wValue;
+                       spin_unlock(&port->port_lock);
+               }
                break;
 
        default:
+               /* NOTE:  strictly speaking, we should accept AT-commands
+                * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
+                * But our call management descriptor says we don't handle
+                * call management, so we should be able to get by without
+                * handling those "required" commands (except by stalling).
+                */
                pr_err("gs_setup: unknown class request, "
                                "type=%02x, request=%02x, value=%04x, "
                                "index=%04x, length=%d\n",
@@ -1719,6 +1734,42 @@ static int gs_setup_class(struct usb_gadget *gadget,
        return ret;
 }
 
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+               struct usb_request *req)
+{
+       struct gs_dev *dev = ep->driver_data;
+       struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
+
+       switch (req->status) {
+       case 0:
+               /* normal completion */
+               if (req->actual != sizeof(port->port_line_coding))
+                       usb_ep_set_halt(ep);
+               else if (port) {
+                       struct usb_cdc_line_coding      *value = req->buf;
+
+                       /* REVISIT:  we currently just remember this data.
+                        * If we change that, (a) validate it first, then
+                        * (b) update whatever hardware needs updating.
+                        */
+                       spin_lock(&port->port_lock);
+                       port->port_line_coding = *value;
+                       spin_unlock(&port->port_lock);
+               }
+               break;
+
+       case -ESHUTDOWN:
+               /* disconnect */
+               gs_free_req(ep, req);
+               break;
+
+       default:
+               /* unexpected */
+               break;
+       }
+       return;
+}
+
 /*
  * gs_setup_complete
  */
@@ -1906,6 +1957,11 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                }
        }
 
+       /* REVISIT the ACM mode should be able to actually *issue* some
+        * notifications, for at least serial state change events if
+        * not also for network connection; say so in bmCapabilities.
+        */
+
        pr_info("gs_set_config: %s configured, %s speed %s config\n",
                GS_LONG_NAME,
                gadget->speed == USB_SPEED_HIGH ? "high" : "full",
index d3d4f4048e6c39f7f958e263cf1761d194c25d34..fce4924dbbe88b6c49dbea3fe33221e224aece05 100644 (file)
@@ -23,9 +23,7 @@
 /*
  * Gadget Zero only needs two bulk endpoints, and is an example of how you
  * can write a hardware-agnostic gadget driver running inside a USB device.
- *
- * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
- * affect most of the driver.
+ * Some hardware details are visible, but don't affect most of the driver.
  *
  * Use it with the Linux host/master side "usbtest" driver to get a basic
  * functional test of your device-side usb stack, or with "usb-skeleton".
@@ -37,6 +35,7 @@
  *   buflen=N          default N=4096, buffer size used
  *   qlen=N            default N=32, how many buffers in the loopback queue
  *   loopdefault       default false, list loopback config first
+ *   autoresume=N      default N=0, seconds before triggering remote wakeup
  *
  * Many drivers will only have one configuration, letting them be much
  * simpler if they also don't support high speed operation (like this
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_VERSION         "Lughnasadh, 2007"
+#define DRIVER_VERSION         "Earth Day 2008"
 
-static const char shortname [] = "zero";
-static const char longname [] = "Gadget Zero";
+static const char shortname[] = "zero";
+static const char longname[] = "Gadget Zero";
 
-static const char source_sink [] = "source and sink data";
-static const char loopback [] = "loop input to output";
+static const char source_sink[] = "source and sink data";
+static const char loopback[] = "loop input to output";
 
 /*-------------------------------------------------------------------------*/
 
@@ -120,16 +119,16 @@ static unsigned buflen = 4096;
 static unsigned qlen = 32;
 static unsigned pattern = 0;
 
-module_param (buflen, uint, S_IRUGO);
-module_param (qlen, uint, S_IRUGO);
-module_param (pattern, uint, S_IRUGO|S_IWUSR);
+module_param(buflen, uint, S_IRUGO);
+module_param(qlen, uint, S_IRUGO);
+module_param(pattern, uint, S_IRUGO|S_IWUSR);
 
 /*
  * if it's nonzero, autoresume says how many seconds to wait
  * before trying to wake up the host after suspend.
  */
 static unsigned autoresume = 0;
-module_param (autoresume, uint, 0);
+module_param(autoresume, uint, 0);
 
 /*
  * Normally the "loopback" configuration is second (index 1) so
@@ -138,8 +137,7 @@ module_param (autoresume, uint, 0);
  * Or controllers (like superh) that only support one config.
  */
 static int loopdefault = 0;
-
-module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
+module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
 
 /*-------------------------------------------------------------------------*/
 
@@ -176,24 +174,22 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
 #define        CONFIG_SOURCE_SINK      3
 #define        CONFIG_LOOPBACK         2
 
-static struct usb_device_descriptor
-device_desc = {
+static struct usb_device_descriptor device_desc = {
        .bLength =              sizeof device_desc,
        .bDescriptorType =      USB_DT_DEVICE,
 
-       .bcdUSB =               __constant_cpu_to_le16 (0x0200),
+       .bcdUSB =               __constant_cpu_to_le16(0x0200),
        .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
 
-       .idVendor =             __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
-       .idProduct =            __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
+       .idVendor =             __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+       .idProduct =            __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
        .iManufacturer =        STRING_MANUFACTURER,
        .iProduct =             STRING_PRODUCT,
        .iSerialNumber =        STRING_SERIAL,
        .bNumConfigurations =   2,
 };
 
-static struct usb_config_descriptor
-source_sink_config = {
+static struct usb_config_descriptor source_sink_config = {
        .bLength =              sizeof source_sink_config,
        .bDescriptorType =      USB_DT_CONFIG,
 
@@ -205,8 +201,7 @@ source_sink_config = {
        .bMaxPower =            1,      /* self-powered */
 };
 
-static struct usb_config_descriptor
-loopback_config = {
+static struct usb_config_descriptor loopback_config = {
        .bLength =              sizeof loopback_config,
        .bDescriptorType =      USB_DT_CONFIG,
 
@@ -218,8 +213,7 @@ loopback_config = {
        .bMaxPower =            1,      /* self-powered */
 };
 
-static struct usb_otg_descriptor
-otg_descriptor = {
+static struct usb_otg_descriptor otg_descriptor = {
        .bLength =              sizeof otg_descriptor,
        .bDescriptorType =      USB_DT_OTG,
 
@@ -228,8 +222,7 @@ otg_descriptor = {
 
 /* one interface in each configuration */
 
-static const struct usb_interface_descriptor
-source_sink_intf = {
+static const struct usb_interface_descriptor source_sink_intf = {
        .bLength =              sizeof source_sink_intf,
        .bDescriptorType =      USB_DT_INTERFACE,
 
@@ -238,8 +231,7 @@ source_sink_intf = {
        .iInterface =           STRING_SOURCE_SINK,
 };
 
-static const struct usb_interface_descriptor
-loopback_intf = {
+static const struct usb_interface_descriptor loopback_intf = {
        .bLength =              sizeof loopback_intf,
        .bDescriptorType =      USB_DT_INTERFACE,
 
@@ -250,8 +242,7 @@ loopback_intf = {
 
 /* two full speed bulk endpoints; their use is config-dependent */
 
-static struct usb_endpoint_descriptor
-fs_source_desc = {
+static struct usb_endpoint_descriptor fs_source_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
 
@@ -259,8 +250,7 @@ fs_source_desc = {
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor
-fs_sink_desc = {
+static struct usb_endpoint_descriptor fs_sink_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
 
@@ -268,7 +258,7 @@ fs_sink_desc = {
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
 };
 
-static const struct usb_descriptor_header *fs_source_sink_function [] = {
+static const struct usb_descriptor_header *fs_source_sink_function[] = {
        (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &source_sink_intf,
        (struct usb_descriptor_header *) &fs_sink_desc,
@@ -276,7 +266,7 @@ static const struct usb_descriptor_header *fs_source_sink_function [] = {
        NULL,
 };
 
-static const struct usb_descriptor_header *fs_loopback_function [] = {
+static const struct usb_descriptor_header *fs_loopback_function[] = {
        (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &loopback_intf,
        (struct usb_descriptor_header *) &fs_sink_desc,
@@ -293,36 +283,33 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
  * for the config descriptor.
  */
 
-static struct usb_endpoint_descriptor
-hs_source_desc = {
+static struct usb_endpoint_descriptor hs_source_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
 
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       __constant_cpu_to_le16 (512),
+       .wMaxPacketSize =       __constant_cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor
-hs_sink_desc = {
+static struct usb_endpoint_descriptor hs_sink_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
 
        .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       __constant_cpu_to_le16 (512),
+       .wMaxPacketSize =       __constant_cpu_to_le16(512),
 };
 
-static struct usb_qualifier_descriptor
-dev_qualifier = {
+static struct usb_qualifier_descriptor dev_qualifier = {
        .bLength =              sizeof dev_qualifier,
        .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
 
-       .bcdUSB =               __constant_cpu_to_le16 (0x0200),
+       .bcdUSB =               __constant_cpu_to_le16(0x0200),
        .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
 
        .bNumConfigurations =   2,
 };
 
-static const struct usb_descriptor_header *hs_source_sink_function [] = {
+static const struct usb_descriptor_header *hs_source_sink_function[] = {
        (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &source_sink_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
@@ -330,7 +317,7 @@ static const struct usb_descriptor_header *hs_source_sink_function [] = {
        NULL,
 };
 
-static const struct usb_descriptor_header *hs_loopback_function [] = {
+static const struct usb_descriptor_header *hs_loopback_function[] = {
        (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &loopback_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
@@ -355,7 +342,7 @@ static char serial[] = "0123456789.0123456789.0123456789";
 
 
 /* static strings, in UTF-8 */
-static struct usb_string               strings [] = {
+static struct usb_string strings[] = {
        { STRING_MANUFACTURER, manufacturer, },
        { STRING_PRODUCT, longname, },
        { STRING_SERIAL, serial, },
@@ -364,7 +351,7 @@ static struct usb_string            strings [] = {
        {  }                    /* end of list */
 };
 
-static struct usb_gadget_strings       stringtab = {
+static struct usb_gadget_strings stringtab = {
        .language       = 0x0409,       /* en-us */
        .strings        = strings,
 };
@@ -387,8 +374,7 @@ static struct usb_gadget_strings    stringtab = {
  * high bandwidth modes at high speed.  (Maybe work like Intel's test
  * device?)
  */
-static int
-config_buf (struct usb_gadget *gadget,
+static int config_buf(struct usb_gadget *gadget,
                u8 *buf, u8 type, unsigned index)
 {
        int                             is_source_sink;
@@ -419,7 +405,7 @@ config_buf (struct usb_gadget *gadget,
        if (!gadget_is_otg(gadget))
                function++;
 
-       len = usb_gadget_config_buf (is_source_sink
+       len = usb_gadget_config_buf(is_source_sink
                                        ? &source_sink_config
                                        : &loopback_config,
                        buf, USB_BUFSIZ, function);
@@ -431,27 +417,26 @@ config_buf (struct usb_gadget *gadget,
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_request *
-alloc_ep_req (struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
 {
        struct usb_request      *req;
 
-       req = usb_ep_alloc_request (ep, GFP_ATOMIC);
+       req = usb_ep_alloc_request(ep, GFP_ATOMIC);
        if (req) {
                req->length = length;
                req->buf = kmalloc(length, GFP_ATOMIC);
                if (!req->buf) {
-                       usb_ep_free_request (ep, req);
+                       usb_ep_free_request(ep, req);
                        req = NULL;
                }
        }
        return req;
 }
 
-static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
 {
        kfree(req->buf);
-       usb_ep_free_request (ep, req);
+       usb_ep_free_request(ep, req);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -472,7 +457,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
 /* optionally require specific source/sink data patterns  */
 
 static int
-check_read_data (
+check_read_data(
        struct zero_dev         *dev,
        struct usb_ep           *ep,
        struct usb_request      *req
@@ -498,8 +483,8 @@ check_read_data (
                                continue;
                        break;
                }
-               ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
-               usb_ep_set_halt (ep);
+               ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
+               usb_ep_set_halt(ep);
                return -EINVAL;
        }
        return 0;
@@ -512,7 +497,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
 
        switch (pattern) {
        case 0:
-               memset (req->buf, 0, req->length);
+               memset(req->buf, 0, req->length);
                break;
        case 1:
                for  (i = 0; i < req->length; i++)
@@ -525,7 +510,7 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
  * irq delay between end of one request and start of the next.
  * that prevents using hardware dma queues.
  */
-static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
+static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
 {
        struct zero_dev *dev = ep->driver_data;
        int             status = req->status;
@@ -534,8 +519,8 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
 
        case 0:                         /* normal completion? */
                if (ep == dev->out_ep) {
-                       check_read_data (dev, ep, req);
-                       memset (req->buf, 0x55, req->length);
+                       check_read_data(dev, ep, req);
+                       memset(req->buf, 0x55, req->length);
                } else
                        reinit_write_data(ep, req);
                break;
@@ -544,11 +529,11 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
        case -ECONNABORTED:             /* hardware forced ep reset */
        case -ECONNRESET:               /* request dequeued */
        case -ESHUTDOWN:                /* disconnect from host */
-               VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+               VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
                                req->actual, req->length);
                if (ep == dev->out_ep)
-                       check_read_data (dev, ep, req);
-               free_ep_req (ep, req);
+                       check_read_data(dev, ep, req);
+               free_ep_req(ep, req);
                return;
 
        case -EOVERFLOW:                /* buffer overrun on read means that
@@ -557,18 +542,18 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
                                         */
        default:
 #if 1
-               DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+               DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
                                status, req->actual, req->length);
 #endif
        case -EREMOTEIO:                /* short read */
                break;
        }
 
-       status = usb_ep_queue (ep, req, GFP_ATOMIC);
+       status = usb_ep_queue(ep, req, GFP_ATOMIC);
        if (status) {
-               ERROR (dev, "kill %s:  resubmit %d bytes --> %d\n",
+               ERROR(dev, "kill %s:  resubmit %d bytes --> %d\n",
                                ep->name, req->length, status);
-               usb_ep_set_halt (ep);
+               usb_ep_set_halt(ep);
                /* FIXME recover later ... somehow */
        }
 }
@@ -578,24 +563,24 @@ static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
        struct usb_request      *req;
        int                     status;
 
-       req = alloc_ep_req (ep, buflen);
+       req = alloc_ep_req(ep, buflen);
        if (!req)
                return NULL;
 
-       memset (req->buf, 0, req->length);
+       memset(req->buf, 0, req->length);
        req->complete = source_sink_complete;
 
-       if (strcmp (ep->name, EP_IN_NAME) == 0)
+       if (strcmp(ep->name, EP_IN_NAME) == 0)
                reinit_write_data(ep, req);
        else
-               memset (req->buf, 0x55, req->length);
+               memset(req->buf, 0x55, req->length);
 
        status = usb_ep_queue(ep, req, GFP_ATOMIC);
        if (status) {
                struct zero_dev *dev = ep->driver_data;
 
-               ERROR (dev, "start %s --> %d\n", ep->name, status);
-               free_ep_req (ep, req);
+               ERROR(dev, "start %s --> %d\n", ep->name, status);
+               free_ep_req(ep, req);
                req = NULL;
        }
 
@@ -608,34 +593,34 @@ static int set_source_sink_config(struct zero_dev *dev)
        struct usb_ep           *ep;
        struct usb_gadget       *gadget = dev->gadget;
 
-       gadget_for_each_ep (ep, gadget) {
+       gadget_for_each_ep(ep, gadget) {
                const struct usb_endpoint_descriptor    *d;
 
                /* one endpoint writes (sources) zeroes in (to the host) */
-               if (strcmp (ep->name, EP_IN_NAME) == 0) {
-                       d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
-                       result = usb_ep_enable (ep, d);
+               if (strcmp(ep->name, EP_IN_NAME) == 0) {
+                       d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+                       result = usb_ep_enable(ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
                                if (source_sink_start_ep(ep) != NULL) {
                                        dev->in_ep = ep;
                                        continue;
                                }
-                               usb_ep_disable (ep);
+                               usb_ep_disable(ep);
                                result = -EIO;
                        }
 
                /* one endpoint reads (sinks) anything out (from the host) */
-               } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
-                       d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
-                       result = usb_ep_enable (ep, d);
+               } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+                       d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+                       result = usb_ep_enable(ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
                                if (source_sink_start_ep(ep) != NULL) {
                                        dev->out_ep = ep;
                                        continue;
                                }
-                               usb_ep_disable (ep);
+                               usb_ep_disable(ep);
                                result = -EIO;
                        }
 
@@ -644,11 +629,11 @@ static int set_source_sink_config(struct zero_dev *dev)
                        continue;
 
                /* stop on error */
-               ERROR (dev, "can't start %s, result %d\n", ep->name, result);
+               ERROR(dev, "can't start %s, result %d\n", ep->name, result);
                break;
        }
        if (result == 0)
-               DBG (dev, "buflen %d\n", buflen);
+               DBG(dev, "buflen %d\n", buflen);
 
        /* caller is responsible for cleanup on error */
        return result;
@@ -656,7 +641,7 @@ static int set_source_sink_config(struct zero_dev *dev)
 
 /*-------------------------------------------------------------------------*/
 
-static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
+static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
 {
        struct zero_dev *dev = ep->driver_data;
        int             status = req->status;
@@ -668,19 +653,19 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
                        /* loop this OUT packet back IN to the host */
                        req->zero = (req->actual < req->length);
                        req->length = req->actual;
-                       status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+                       status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
                        if (status == 0)
                                return;
 
                        /* "should never get here" */
-                       ERROR (dev, "can't loop %s to %s: %d\n",
+                       ERROR(dev, "can't loop %s to %s: %d\n",
                                ep->name, dev->in_ep->name,
                                status);
                }
 
                /* queue the buffer for some later OUT packet */
                req->length = buflen;
-               status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
+               status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
                if (status == 0)
                        return;
 
@@ -688,7 +673,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
                /* FALLTHROUGH */
 
        default:
-               ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+               ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name,
                                status, req->actual, req->length);
                /* FALLTHROUGH */
 
@@ -700,7 +685,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
        case -ECONNABORTED:             /* hardware forced ep reset */
        case -ECONNRESET:               /* request dequeued */
        case -ESHUTDOWN:                /* disconnect from host */
-               free_ep_req (ep, req);
+               free_ep_req(ep, req);
                return;
        }
 }
@@ -711,13 +696,13 @@ static int set_loopback_config(struct zero_dev *dev)
        struct usb_ep           *ep;
        struct usb_gadget       *gadget = dev->gadget;
 
-       gadget_for_each_ep (ep, gadget) {
+       gadget_for_each_ep(ep, gadget) {
                const struct usb_endpoint_descriptor    *d;
 
                /* one endpoint writes data back IN to the host */
-               if (strcmp (ep->name, EP_IN_NAME) == 0) {
-                       d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
-                       result = usb_ep_enable (ep, d);
+               if (strcmp(ep->name, EP_IN_NAME) == 0) {
+                       d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+                       result = usb_ep_enable(ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
                                dev->in_ep = ep;
@@ -725,9 +710,9 @@ static int set_loopback_config(struct zero_dev *dev)
                        }
 
                /* one endpoint just reads OUT packets */
-               } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
-                       d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
-                       result = usb_ep_enable (ep, d);
+               } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+                       d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+                       result = usb_ep_enable(ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
                                dev->out_ep = ep;
@@ -739,7 +724,7 @@ static int set_loopback_config(struct zero_dev *dev)
                        continue;
 
                /* stop on error */
-               ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+               ERROR(dev, "can't enable %s, result %d\n", ep->name, result);
                break;
        }
 
@@ -753,19 +738,19 @@ static int set_loopback_config(struct zero_dev *dev)
 
                ep = dev->out_ep;
                for (i = 0; i < qlen && result == 0; i++) {
-                       req = alloc_ep_req (ep, buflen);
+                       req = alloc_ep_req(ep, buflen);
                        if (req) {
                                req->complete = loopback_complete;
-                               result = usb_ep_queue (ep, req, GFP_ATOMIC);
+                               result = usb_ep_queue(ep, req, GFP_ATOMIC);
                                if (result)
-                                       DBG (dev, "%s queue req --> %d\n",
+                                       DBG(dev, "%s queue req --> %d\n",
                                                        ep->name, result);
                        } else
                                result = -ENOMEM;
                }
        }
        if (result == 0)
-               DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+               DBG(dev, "qlen %d, buflen %d\n", qlen, buflen);
 
        /* caller is responsible for cleanup on error */
        return result;
@@ -773,26 +758,26 @@ static int set_loopback_config(struct zero_dev *dev)
 
 /*-------------------------------------------------------------------------*/
 
-static void zero_reset_config (struct zero_dev *dev)
+static void zero_reset_config(struct zero_dev *dev)
 {
        if (dev->config == 0)
                return;
 
-       DBG (dev, "reset config\n");
+       DBG(dev, "reset config\n");
 
        /* just disable endpoints, forcing completion of pending i/o.
         * all our completion handlers free their requests in this case.
         */
        if (dev->in_ep) {
-               usb_ep_disable (dev->in_ep);
+               usb_ep_disable(dev->in_ep);
                dev->in_ep = NULL;
        }
        if (dev->out_ep) {
-               usb_ep_disable (dev->out_ep);
+               usb_ep_disable(dev->out_ep);
                dev->out_ep = NULL;
        }
        dev->config = 0;
-       del_timer (&dev->resume);
+       del_timer(&dev->resume);
 }
 
 /* change our operational config.  this code must agree with the code
@@ -813,12 +798,12 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
        if (number == dev->config)
                return 0;
 
-       if (gadget_is_sa1100 (gadget) && dev->config) {
+       if (gadget_is_sa1100(gadget) && dev->config) {
                /* tx fifo is full, but we can't clear it...*/
                ERROR(dev, "can't change configurations\n");
                return -ESPIPE;
        }
-       zero_reset_config (dev);
+       zero_reset_config(dev);
 
        switch (number) {
        case CONFIG_SOURCE_SINK:
@@ -837,7 +822,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
        if (!result && (!dev->in_ep || !dev->out_ep))
                result = -ENODEV;
        if (result)
-               zero_reset_config (dev);
+               zero_reset_config(dev);
        else {
                char *speed;
 
@@ -849,7 +834,7 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
                }
 
                dev->config = number;
-               INFO (dev, "%s speed config #%d: %s\n", speed, number,
+               INFO(dev, "%s speed config #%d: %s\n", speed, number,
                                (number == CONFIG_SOURCE_SINK)
                                        ? source_sink : loopback);
        }
@@ -858,10 +843,10 @@ static int zero_set_config(struct zero_dev *dev, unsigned number)
 
 /*-------------------------------------------------------------------------*/
 
-static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
+static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req)
 {
        if (req->status || req->actual != req->length)
-               DBG ((struct zero_dev *) ep->driver_data,
+               DBG((struct zero_dev *) ep->driver_data,
                                "setup complete --> %d, %d/%d\n",
                                req->status, req->actual, req->length);
 }
@@ -874,9 +859,9 @@ static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
  * the work is in config-specific setup.
  */
 static int
-zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 {
-       struct zero_dev         *dev = get_gadget_data (gadget);
+       struct zero_dev         *dev = get_gadget_data(gadget);
        struct usb_request      *req = dev->req;
        int                     value = -EOPNOTSUPP;
        u16                     w_index = le16_to_cpu(ctrl->wIndex);
@@ -895,14 +880,14 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                switch (w_value >> 8) {
 
                case USB_DT_DEVICE:
-                       value = min (w_length, (u16) sizeof device_desc);
-                       memcpy (req->buf, &device_desc, value);
+                       value = min(w_length, (u16) sizeof device_desc);
+                       memcpy(req->buf, &device_desc, value);
                        break;
                case USB_DT_DEVICE_QUALIFIER:
                        if (!gadget_is_dualspeed(gadget))
                                break;
-                       value = min (w_length, (u16) sizeof dev_qualifier);
-                       memcpy (req->buf, &dev_qualifier, value);
+                       value = min(w_length, (u16) sizeof dev_qualifier);
+                       memcpy(req->buf, &dev_qualifier, value);
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
@@ -910,11 +895,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                break;
                        // FALLTHROUGH
                case USB_DT_CONFIG:
-                       value = config_buf (gadget, req->buf,
+                       value = config_buf(gadget, req->buf,
                                        w_value >> 8,
                                        w_value & 0xff);
                        if (value >= 0)
-                               value = min (w_length, (u16) value);
+                               value = min(w_length, (u16) value);
                        break;
 
                case USB_DT_STRING:
@@ -923,10 +908,10 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                         * add string tables for other languages, using
                         * any UTF-8 characters
                         */
-                       value = usb_gadget_get_string (&stringtab,
+                       value = usb_gadget_get_string(&stringtab,
                                        w_value & 0xff, req->buf);
                        if (value >= 0)
-                               value = min (w_length, (u16) value);
+                               value = min(w_length, (u16) value);
                        break;
                }
                break;
@@ -936,20 +921,20 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                if (ctrl->bRequestType != 0)
                        goto unknown;
                if (gadget->a_hnp_support)
-                       DBG (dev, "HNP available\n");
+                       DBG(dev, "HNP available\n");
                else if (gadget->a_alt_hnp_support)
-                       DBG (dev, "HNP needs a different root port\n");
+                       DBG(dev, "HNP needs a different root port\n");
                else
-                       VDBG (dev, "HNP inactive\n");
-               spin_lock (&dev->lock);
+                       VDBG(dev, "HNP inactive\n");
+               spin_lock(&dev->lock);
                value = zero_set_config(dev, w_value);
-               spin_unlock (&dev->lock);
+               spin_unlock(&dev->lock);
                break;
        case USB_REQ_GET_CONFIGURATION:
                if (ctrl->bRequestType != USB_DIR_IN)
                        goto unknown;
                *(u8 *)req->buf = dev->config;
-               value = min (w_length, (u16) 1);
+               value = min(w_length, (u16) 1);
                break;
 
        /* until we add altsetting support, or other interfaces,
@@ -959,7 +944,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        case USB_REQ_SET_INTERFACE:
                if (ctrl->bRequestType != USB_RECIP_INTERFACE)
                        goto unknown;
-               spin_lock (&dev->lock);
+               spin_lock(&dev->lock);
                if (dev->config && w_index == 0 && w_value == 0) {
                        u8              config = dev->config;
 
@@ -970,11 +955,11 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                         * if we had more than one interface we couldn't
                         * use this "reset the config" shortcut.
                         */
-                       zero_reset_config (dev);
+                       zero_reset_config(dev);
                        zero_set_config(dev, config);
                        value = 0;
                }
-               spin_unlock (&dev->lock);
+               spin_unlock(&dev->lock);
                break;
        case USB_REQ_GET_INTERFACE:
                if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
@@ -986,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        break;
                }
                *(u8 *)req->buf = 0;
-               value = min (w_length, (u16) 1);
+               value = min(w_length, (u16) 1);
                break;
 
        /*
@@ -1018,7 +1003,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 
        default:
 unknown:
-               VDBG (dev,
+               VDBG(dev,
                        "unknown control req%02x.%02x v%04x i%04x l%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
                        w_value, w_index, w_length);
@@ -1028,11 +1013,11 @@ unknown:
        if (value >= 0) {
                req->length = value;
                req->zero = value < w_length;
-               value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+               value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
                if (value < 0) {
-                       DBG (dev, "ep_queue --> %d\n", value);
+                       DBG(dev, "ep_queue --> %d\n", value);
                        req->status = 0;
-                       zero_setup_complete (gadget->ep0, req);
+                       zero_setup_complete(gadget->ep0, req);
                }
        }
 
@@ -1040,28 +1025,26 @@ unknown:
        return value;
 }
 
-static void
-zero_disconnect (struct usb_gadget *gadget)
+static void zero_disconnect(struct usb_gadget *gadget)
 {
-       struct zero_dev         *dev = get_gadget_data (gadget);
+       struct zero_dev         *dev = get_gadget_data(gadget);
        unsigned long           flags;
 
-       spin_lock_irqsave (&dev->lock, flags);
-       zero_reset_config (dev);
+       spin_lock_irqsave(&dev->lock, flags);
+       zero_reset_config(dev);
 
        /* a more significant application might have some non-usb
         * activities to quiesce here, saving resources like power
         * or pushing the notification up a network stack.
         */
-       spin_unlock_irqrestore (&dev->lock, flags);
+       spin_unlock_irqrestore(&dev->lock, flags);
 
        /* next we may get setup() calls to enumerate new connections;
         * or an unbind() during shutdown (including removing module).
         */
 }
 
-static void
-zero_autoresume (unsigned long _dev)
+static void zero_autoresume(unsigned long _dev)
 {
        struct zero_dev *dev = (struct zero_dev *) _dev;
        int             status;
@@ -1070,32 +1053,30 @@ zero_autoresume (unsigned long _dev)
         * more significant than just a timer firing...
         */
        if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
-               status = usb_gadget_wakeup (dev->gadget);
-               DBG (dev, "wakeup --> %d\n", status);
+               status = usb_gadget_wakeup(dev->gadget);
+               DBG(dev, "wakeup --> %d\n", status);
        }
 }
 
 /*-------------------------------------------------------------------------*/
 
-static void /* __init_or_exit */
-zero_unbind (struct usb_gadget *gadget)
+static void zero_unbind(struct usb_gadget *gadget)
 {
-       struct zero_dev         *dev = get_gadget_data (gadget);
+       struct zero_dev         *dev = get_gadget_data(gadget);
 
-       DBG (dev, "unbind\n");
+       DBG(dev, "unbind\n");
 
        /* we've already been disconnected ... no i/o is active */
        if (dev->req) {
                dev->req->length = USB_BUFSIZ;
-               free_ep_req (gadget->ep0, dev->req);
+               free_ep_req(gadget->ep0, dev->req);
        }
-       del_timer_sync (&dev->resume);
-       kfree (dev);
-       set_gadget_data (gadget, NULL);
+       del_timer_sync(&dev->resume);
+       kfree(dev);
+       set_gadget_data(gadget, NULL);
 }
 
-static int __init
-zero_bind (struct usb_gadget *gadget)
+static int __init zero_bind(struct usb_gadget *gadget)
 {
        struct zero_dev         *dev;
        struct usb_ep           *ep;
@@ -1111,8 +1092,8 @@ zero_bind (struct usb_gadget *gadget)
         * autoconfigure on any sane usb controller driver,
         * but there may also be important quirks to address.
         */
-       usb_ep_autoconfig_reset (gadget);
-       ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+       usb_ep_autoconfig_reset(gadget);
+       ep = usb_ep_autoconfig(gadget, &fs_source_desc);
        if (!ep) {
 autoconf_fail:
                pr_err("%s: can't autoconfigure on %s\n",
@@ -1122,15 +1103,15 @@ autoconf_fail:
        EP_IN_NAME = ep->name;
        ep->driver_data = ep;   /* claim */
 
-       ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+       ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
        if (!ep)
                goto autoconf_fail;
        EP_OUT_NAME = ep->name;
        ep->driver_data = ep;   /* claim */
 
-       gcnum = usb_gadget_controller_number (gadget);
+       gcnum = usb_gadget_controller_number(gadget);
        if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
+               device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
        else {
                /* gadget zero is so simple (for now, no altsettings) that
                 * it SHOULD NOT have problems with bulk-capable hardware.
@@ -1141,7 +1122,7 @@ autoconf_fail:
                 */
                pr_warning("%s: controller '%s' not recognized\n",
                        shortname, gadget->name);
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
+               device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
        }
 
 
@@ -1149,12 +1130,16 @@ autoconf_fail:
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
-       spin_lock_init (&dev->lock);
+       spin_lock_init(&dev->lock);
        dev->gadget = gadget;
-       set_gadget_data (gadget, dev);
+       set_gadget_data(gadget, dev);
+
+       init_timer(&dev->resume);
+       dev->resume.function = zero_autoresume;
+       dev->resume.data = (unsigned long) dev;
 
        /* preallocate control response and buffer */
-       dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+       dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
        if (!dev->req)
                goto enomem;
        dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
@@ -1182,11 +1167,8 @@ autoconf_fail:
                loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
 
-       usb_gadget_set_selfpowered (gadget);
+       usb_gadget_set_selfpowered(gadget);
 
-       init_timer (&dev->resume);
-       dev->resume.function = zero_autoresume;
-       dev->resume.data = (unsigned long) dev;
        if (autoresume) {
                source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1194,45 +1176,43 @@ autoconf_fail:
 
        gadget->ep0->driver_data = dev;
 
-       INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
-       INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
+       INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+       INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
                EP_OUT_NAME, EP_IN_NAME);
 
-       snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
+       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
                init_utsname()->sysname, init_utsname()->release,
                gadget->name);
 
        return 0;
 
 enomem:
-       zero_unbind (gadget);
+       zero_unbind(gadget);
        return -ENOMEM;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static void
-zero_suspend (struct usb_gadget *gadget)
+static void zero_suspend(struct usb_gadget *gadget)
 {
-       struct zero_dev         *dev = get_gadget_data (gadget);
+       struct zero_dev         *dev = get_gadget_data(gadget);
 
        if (gadget->speed == USB_SPEED_UNKNOWN)
                return;
 
        if (autoresume) {
-               mod_timer (&dev->resume, jiffies + (HZ * autoresume));
-               DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+               mod_timer(&dev->resume, jiffies + (HZ * autoresume));
+               DBG(dev, "suspend, wakeup in %d seconds\n", autoresume);
        } else
-               DBG (dev, "suspend\n");
+               DBG(dev, "suspend\n");
 }
 
-static void
-zero_resume (struct usb_gadget *gadget)
+static void zero_resume(struct usb_gadget *gadget)
 {
-       struct zero_dev         *dev = get_gadget_data (gadget);
+       struct zero_dev         *dev = get_gadget_data(gadget);
 
-       DBG (dev, "resume\n");
-       del_timer (&dev->resume);
+       DBG(dev, "resume\n");
+       del_timer(&dev->resume);
 }
 
 
@@ -1264,15 +1244,15 @@ MODULE_AUTHOR("David Brownell");
 MODULE_LICENSE("GPL");
 
 
-static int __init init (void)
+static int __init init(void)
 {
-       return usb_gadget_register_driver (&zero_driver);
+       return usb_gadget_register_driver(&zero_driver);
 }
-module_init (init);
+module_init(init);
 
-static void __exit cleanup (void)
+static void __exit cleanup(void)
 {
-       usb_gadget_unregister_driver (&zero_driver);
+       usb_gadget_unregister_driver(&zero_driver);
 }
-module_exit (cleanup);
+module_exit(cleanup);
 
index 0b87480dd713af0671575ce9cd055b00350ad384..33b467a8352dc95892b09dba5a023d64968ebc1f 100644 (file)
@@ -4,6 +4,19 @@
 comment "USB Host Controller Drivers"
        depends on USB
 
+config USB_C67X00_HCD
+       tristate "Cypress C67x00 HCD support"
+       depends on USB
+       help
+         The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
+         host/peripheral/OTG USB controllers.
+
+         Enable this option to support this chip in host controller mode.
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called c67x00.
+
 config USB_EHCI_HCD
        tristate "EHCI HCD (USB 2.0) support"
        depends on USB && USB_ARCH_HAS_EHCI
@@ -95,6 +108,32 @@ config USB_ISP116X_HCD
          To compile this driver as a module, choose M here: the
          module will be called isp116x-hcd.
 
+config USB_ISP1760_HCD
+       tristate "ISP 1760 HCD support"
+       depends on USB && EXPERIMENTAL
+       ---help---
+         The ISP1760 chip is a USB 2.0 host controller.
+
+         This driver does not support isochronous transfers or OTG.
+
+         To compile this driver as a module, choose M here: the
+         module will be called isp1760-hcd.
+
+config USB_ISP1760_PCI
+       bool "Support for the PCI bus"
+       depends on USB_ISP1760_HCD && PCI
+       ---help---
+         Enables support for the device present on the PCI bus.
+         This should only be required if you happen to have the eval kit from
+         NXP and you are going to test it.
+
+config USB_ISP1760_OF
+       bool "Support for the OF platform bus"
+       depends on USB_ISP1760_HCD && OF
+       ---help---
+         Enables support for the device present on the PowerPC
+         OpenFirmware platform bus.
+
 config USB_OHCI_HCD
        tristate "OHCI HCD support"
        depends on USB && USB_ARCH_HAS_OHCI
index bb8e9d44f371243c91097cae75ac3c5b931a757d..f1edda2dcfdecdaf49f91f775ad8d11a981d110a 100644 (file)
@@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y)
        EXTRA_CFLAGS            += -DDEBUG
 endif
 
+isp1760-objs := isp1760-hcd.o isp1760-if.o
+
 obj-$(CONFIG_PCI)              += pci-quirks.o
 
 obj-$(CONFIG_USB_EHCI_HCD)     += ehci-hcd.o
@@ -16,4 +18,4 @@ obj-$(CONFIG_USB_SL811_HCD)   += sl811-hcd.o
 obj-$(CONFIG_USB_SL811_CS)     += sl811_cs.o
 obj-$(CONFIG_USB_U132_HCD)     += u132-hcd.o
 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-
+obj-$(CONFIG_USB_ISP1760_HCD)  += isp1760.o
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
new file mode 100644 (file)
index 0000000..4ba96c1
--- /dev/null
@@ -0,0 +1,2231 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * However, the code might contain some bugs. What doesn't work for sure is:
+ * - ISO
+ * - OTG
+ e The interrupt line is configured as active low, level.
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/unaligned.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+static struct kmem_cache *qtd_cachep;
+static struct kmem_cache *qh_cachep;
+
+struct isp1760_hcd {
+       u32 hcs_params;
+       spinlock_t              lock;
+       struct inter_packet_info atl_ints[32];
+       struct inter_packet_info int_ints[32];
+       struct memory_chunk memory_pool[BLOCKS];
+
+       /* periodic schedule support */
+#define        DEFAULT_I_TDPS          1024
+       unsigned                periodic_size;
+       unsigned                i_thresh;
+       unsigned long           reset_done;
+       unsigned long           next_statechange;
+};
+
+static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
+{
+       return (struct isp1760_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv)
+{
+       return container_of((void *) priv, struct usb_hcd, hcd_priv);
+}
+
+/* Section 2.2 Host Controller Capability Registers */
+#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
+#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
+#define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_PPC(p)             ((p)&(1 << 4))  /* true: port power control */
+#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+
+/* Section 2.3 Host Controller Operational Registers */
+#define CMD_LRESET     (1<<7)          /* partial reset (no ports, etc) */
+#define CMD_RESET      (1<<1)          /* reset HC not bus */
+#define CMD_RUN                (1<<0)          /* start/stop HC */
+#define STS_PCD                (1<<2)          /* port change detect */
+#define FLAG_CF                (1<<0)          /* true: we'll support "high speed" */
+
+#define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
+#define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
+#define PORT_RESET     (1<<8)          /* reset port */
+#define PORT_SUSPEND   (1<<7)          /* suspend port */
+#define PORT_RESUME    (1<<6)          /* resume it */
+#define PORT_PE                (1<<2)          /* port enable */
+#define PORT_CSC       (1<<1)          /* connect status change */
+#define PORT_CONNECT   (1<<0)          /* device connected */
+#define PORT_RWC_BITS   (PORT_CSC)
+
+struct isp1760_qtd {
+       struct isp1760_qtd *hw_next;
+       u8 packet_type;
+       u8 toggle;
+
+       void *data_buffer;
+       /* the rest is HCD-private */
+       struct list_head qtd_list;
+       struct urb *urb;
+       size_t length;
+
+       /* isp special*/
+       u32 status;
+#define URB_COMPLETE_NOTIFY    (1 << 0)
+#define URB_ENQUEUED           (1 << 1)
+#define URB_TYPE_ATL           (1 << 2)
+#define URB_TYPE_INT           (1 << 3)
+};
+
+struct isp1760_qh {
+       /* first part defined by EHCI spec */
+       struct list_head qtd_list;
+       struct isp1760_hcd *priv;
+
+       /* periodic schedule info */
+       unsigned short period;          /* polling interval */
+       struct usb_device *dev;
+
+       u32 toggle;
+       u32 ping;
+};
+
+#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED)
+
+static unsigned int isp1760_readl(__u32 __iomem *regs)
+{
+       return readl(regs);
+}
+
+static void isp1760_writel(const unsigned int val, __u32 __iomem *regs)
+{
+       writel(val, regs);
+}
+
+/*
+ * The next two copy via MMIO data to/from the device. memcpy_{to|from}io()
+ * doesn't quite work because some people have to enforce 32-bit access
+ */
+static void priv_read_copy(struct isp1760_hcd *priv, u32 *src,
+               __u32 __iomem *dst, u32 offset, u32 len)
+{
+       struct usb_hcd *hcd = priv_to_hcd(priv);
+       u32 val;
+       u8 *buff8;
+
+       if (!src) {
+               printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len);
+               return;
+       }
+       isp1760_writel(offset,  hcd->regs + HC_MEMORY_REG);
+       /* XXX
+        * 90nsec delay, the spec says something how this could be avoided.
+        */
+       mdelay(1);
+
+       while (len >= 4) {
+               *src = __raw_readl(dst);
+               len -= 4;
+               src++;
+               dst++;
+       }
+
+       if (!len)
+               return;
+
+       /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
+        * allocated.
+        */
+       val = isp1760_readl(dst);
+
+       buff8 = (u8 *)src;
+       while (len) {
+
+               *buff8 = val;
+               val >>= 8;
+               len--;
+               buff8++;
+       }
+}
+
+static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src,
+               __u32 __iomem *dst, u32 len)
+{
+       while (len >= 4) {
+               __raw_writel(*src, dst);
+               len -= 4;
+               src++;
+               dst++;
+       }
+
+       if (!len)
+               return;
+       /* in case we have 3, 2 or 1 by left. The buffer is allocated and the
+        * extra bytes should not be read by the HW
+        */
+
+       __raw_writel(*src, dst);
+}
+
+/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+static void init_memory(struct isp1760_hcd *priv)
+{
+       int i;
+       u32 payload;
+
+       payload = 0x1000;
+       for (i = 0; i < BLOCK_1_NUM; i++) {
+               priv->memory_pool[i].start = payload;
+               priv->memory_pool[i].size = BLOCK_1_SIZE;
+               priv->memory_pool[i].free = 1;
+               payload += priv->memory_pool[i].size;
+       }
+
+
+       for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) {
+               priv->memory_pool[i].start = payload;
+               priv->memory_pool[i].size = BLOCK_2_SIZE;
+               priv->memory_pool[i].free = 1;
+               payload += priv->memory_pool[i].size;
+       }
+
+
+       for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) {
+               priv->memory_pool[i].start = payload;
+               priv->memory_pool[i].size = BLOCK_3_SIZE;
+               priv->memory_pool[i].free = 1;
+               payload += priv->memory_pool[i].size;
+       }
+
+       BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE);
+}
+
+static u32 alloc_mem(struct isp1760_hcd *priv, u32 size)
+{
+       int i;
+
+       if (!size)
+               return ISP1760_NULL_POINTER;
+
+       for (i = 0; i < BLOCKS; i++) {
+               if (priv->memory_pool[i].size >= size &&
+                               priv->memory_pool[i].free) {
+
+                       priv->memory_pool[i].free = 0;
+                       return priv->memory_pool[i].start;
+               }
+       }
+
+       printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n",
+                       size);
+       printk(KERN_ERR "Current memory map:\n");
+       for (i = 0; i < BLOCKS; i++) {
+               printk(KERN_ERR "Pool %2d size %4d status: %d\n",
+                               i, priv->memory_pool[i].size,
+                               priv->memory_pool[i].free);
+       }
+       /* XXX maybe -ENOMEM could be possible */
+       BUG();
+       return 0;
+}
+
+static void free_mem(struct isp1760_hcd *priv, u32 mem)
+{
+       int i;
+
+       if (mem == ISP1760_NULL_POINTER)
+               return;
+
+       for (i = 0; i < BLOCKS; i++) {
+               if (priv->memory_pool[i].start == mem) {
+
+                       BUG_ON(priv->memory_pool[i].free);
+
+                       priv->memory_pool[i].free = 1;
+                       return ;
+               }
+       }
+
+       printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n",
+                       mem);
+       BUG();
+}
+
+static void isp1760_init_regs(struct usb_hcd *hcd)
+{
+       isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG);
+       isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+                       HC_ATL_PTD_SKIPMAP_REG);
+       isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+                       HC_INT_PTD_SKIPMAP_REG);
+       isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+                       HC_ISO_PTD_SKIPMAP_REG);
+
+       isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+                       HC_ATL_PTD_DONEMAP_REG);
+       isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+                       HC_INT_PTD_DONEMAP_REG);
+       isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+                       HC_ISO_PTD_DONEMAP_REG);
+}
+
+static int handshake(struct isp1760_hcd *priv, void __iomem *ptr,
+                     u32 mask, u32 done, int usec)
+{
+       u32 result;
+
+       do {
+               result = isp1760_readl(ptr);
+               if (result == ~0)
+                       return -ENODEV;
+               result &= mask;
+               if (result == done)
+                       return 0;
+               udelay(1);
+               usec--;
+       } while (usec > 0);
+       return -ETIMEDOUT;
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset(struct isp1760_hcd *priv)
+{
+       int retval;
+       struct usb_hcd *hcd = priv_to_hcd(priv);
+       u32 command = isp1760_readl(hcd->regs + HC_USBCMD);
+
+       command |= CMD_RESET;
+       isp1760_writel(command, hcd->regs + HC_USBCMD);
+       hcd->state = HC_STATE_HALT;
+       priv->next_statechange = jiffies;
+       retval = handshake(priv, hcd->regs + HC_USBCMD,
+                           CMD_RESET, 0, 250 * 1000);
+       return retval;
+}
+
+static void qh_destroy(struct isp1760_qh *qh)
+{
+       BUG_ON(!list_empty(&qh->qtd_list));
+       kmem_cache_free(qh_cachep, qh);
+}
+
+static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv,
+               gfp_t flags)
+{
+       struct isp1760_qh *qh;
+
+       qh = kmem_cache_zalloc(qh_cachep, flags);
+       if (!qh)
+               return qh;
+
+       INIT_LIST_HEAD(&qh->qtd_list);
+       qh->priv = priv;
+       return qh;
+}
+
+/* magic numbers that can affect system performance */
+#define        EHCI_TUNE_CERR          3       /* 0-3 qtd retries; 0 == don't stop */
+#define        EHCI_TUNE_RL_HS         4       /* nak throttle; see 4.9 */
+#define        EHCI_TUNE_RL_TT         0
+#define        EHCI_TUNE_MULT_HS       1       /* 1-3 transactions/uframe; 4.10.3 */
+#define        EHCI_TUNE_MULT_TT       1
+#define        EHCI_TUNE_FLS           2       /* (small) 256 frame schedule */
+
+/* one-time init, only for memory state */
+static int priv_init(struct usb_hcd *hcd)
+{
+       struct isp1760_hcd              *priv = hcd_to_priv(hcd);
+       u32                     hcc_params;
+
+       spin_lock_init(&priv->lock);
+
+       /*
+        * hw default: 1K periodic list heads, one per frame.
+        * periodic_size can shrink by USBCMD update if hcc_params allows.
+        */
+       priv->periodic_size = DEFAULT_I_TDPS;
+
+       /* controllers may cache some of the periodic schedule ... */
+       hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS);
+       /* full frame cache */
+       if (HCC_ISOC_CACHE(hcc_params))
+               priv->i_thresh = 8;
+       else /* N microframes cached */
+               priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+       return 0;
+}
+
+static int isp1760_hc_setup(struct usb_hcd *hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       int result;
+       u32 scratch;
+
+       isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG);
+       scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG);
+       if (scratch != 0xdeadbabe) {
+               printk(KERN_ERR "ISP1760: Scratch test failed.\n");
+               return -ENODEV;
+       }
+
+       /* pre reset */
+       isp1760_init_regs(hcd);
+
+       /* reset */
+       isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG);
+       mdelay(100);
+
+       isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG);
+       mdelay(100);
+
+       result = ehci_reset(priv);
+       if (result)
+               return result;
+
+       /* Step 11 passed */
+
+       isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG);
+       isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE);
+
+       /* ATL reset */
+       scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+       isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL);
+       mdelay(10);
+       isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL);
+
+       isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL);
+       mdelay(10);
+
+       priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS);
+
+       return priv_init(hcd);
+}
+
+static void isp1760_init_maps(struct usb_hcd *hcd)
+{
+       /*set last maps, for iso its only 1, else 32 tds bitmap*/
+       isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG);
+       isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG);
+       isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG);
+}
+
+static void isp1760_enable_interrupts(struct usb_hcd *hcd)
+{
+       isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG);
+       isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+       isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG);
+       isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+       isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG);
+       isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG);
+       /* step 23 passed */
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       int retval;
+       u32 temp;
+       u32 command;
+       u32 chipid;
+
+       hcd->uses_new_polling = 1;
+       hcd->poll_rh = 0;
+
+       hcd->state = HC_STATE_RUNNING;
+       isp1760_enable_interrupts(hcd);
+       temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+       temp |= FINAL_HW_CONFIG;
+       isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL);
+
+       command = isp1760_readl(hcd->regs + HC_USBCMD);
+       command &= ~(CMD_LRESET|CMD_RESET);
+       command |= CMD_RUN;
+       isp1760_writel(command, hcd->regs + HC_USBCMD);
+
+       retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN,
+                       250 * 1000);
+       if (retval)
+               return retval;
+
+       /*
+        * XXX
+        * Spec says to write FLAG_CF as last config action, priv code grabs
+        * the semaphore while doing so.
+        */
+       down_write(&ehci_cf_port_reset_rwsem);
+       isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG);
+
+       retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF,
+                       250 * 1000);
+       up_write(&ehci_cf_port_reset_rwsem);
+       if (retval)
+               return retval;
+
+       chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG);
+       isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff,
+                       chipid >> 16);
+
+       /* PTD Register Init Part 2, Step 28 */
+       /* enable INTs */
+       isp1760_init_maps(hcd);
+
+       /* GRR this is run-once init(), being done every time the HC starts.
+        * So long as they're part of class devices, we can't do it init()
+        * since the class device isn't created that early.
+        */
+       return 0;
+}
+
+static u32 base_to_chip(u32 base)
+{
+       return ((base - 0x400) >> 3);
+}
+
+static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+                       struct isp1760_qtd *qtd, struct urb *urb,
+                       u32 payload, struct ptd *ptd)
+{
+       u32 dw0;
+       u32 dw1;
+       u32 dw2;
+       u32 dw3;
+       u32 maxpacket;
+       u32 multi;
+       u32 pid_code;
+       u32 rl = RL_COUNTER;
+       u32 nak = NAK_COUNTER;
+
+       /* according to 3.6.2, max packet len can not be > 0x400 */
+       maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+       multi =  1 + ((maxpacket >> 11) & 0x3);
+       maxpacket &= 0x7ff;
+
+       /* DW0 */
+       dw0 = PTD_VALID;
+       dw0 |= PTD_LENGTH(qtd->length);
+       dw0 |= PTD_MAXPACKET(maxpacket);
+       dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe));
+       dw1 = usb_pipeendpoint(urb->pipe) >> 1;
+
+       /* DW1 */
+       dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe));
+
+       pid_code = qtd->packet_type;
+       dw1 |= PTD_PID_TOKEN(pid_code);
+
+       if (usb_pipebulk(urb->pipe))
+               dw1 |= PTD_TRANS_BULK;
+       else if  (usb_pipeint(urb->pipe))
+               dw1 |= PTD_TRANS_INT;
+
+       if (urb->dev->speed != USB_SPEED_HIGH) {
+               /* split transaction */
+
+               dw1 |= PTD_TRANS_SPLIT;
+               if (urb->dev->speed == USB_SPEED_LOW)
+                       dw1 |= PTD_SE_USB_LOSPEED;
+
+               dw1 |= PTD_PORT_NUM(urb->dev->ttport);
+               dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum);
+
+               /* SE bit for Split INT transfers */
+               if (usb_pipeint(urb->pipe) &&
+                               (urb->dev->speed == USB_SPEED_LOW))
+                       dw1 |= 2 << 16;
+
+               dw3 = 0;
+               rl = 0;
+               nak = 0;
+       } else {
+               dw0 |= PTD_MULTI(multi);
+               if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe))
+                       dw3 = qh->ping;
+               else
+                       dw3 = 0;
+       }
+       /* DW2 */
+       dw2 = 0;
+       dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload));
+       dw2 |= PTD_RL_CNT(rl);
+       dw3 |= PTD_NAC_CNT(nak);
+
+       /* DW3 */
+       if (usb_pipecontrol(urb->pipe))
+               dw3 |= PTD_DATA_TOGGLE(qtd->toggle);
+       else
+               dw3 |= qh->toggle;
+
+
+       dw3 |= PTD_ACTIVE;
+       /* Cerr */
+       dw3 |= PTD_CERR(ERR_COUNTER);
+
+       memset(ptd, 0, sizeof(*ptd));
+
+       ptd->dw0 = cpu_to_le32(dw0);
+       ptd->dw1 = cpu_to_le32(dw1);
+       ptd->dw2 = cpu_to_le32(dw2);
+       ptd->dw3 = cpu_to_le32(dw3);
+}
+
+static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+                       struct isp1760_qtd *qtd, struct urb *urb,
+                       u32 payload, struct ptd *ptd)
+{
+       u32 maxpacket;
+       u32 multi;
+       u32 numberofusofs;
+       u32 i;
+       u32 usofmask, usof;
+       u32 period;
+
+       maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+       multi =  1 + ((maxpacket >> 11) & 0x3);
+       maxpacket &= 0x7ff;
+       /* length of the data per uframe */
+       maxpacket = multi * maxpacket;
+
+       numberofusofs = urb->transfer_buffer_length / maxpacket;
+       if (urb->transfer_buffer_length % maxpacket)
+               numberofusofs += 1;
+
+       usofmask = 1;
+       usof = 0;
+       for (i = 0; i < numberofusofs; i++) {
+               usof |= usofmask;
+               usofmask <<= 1;
+       }
+
+       if (urb->dev->speed != USB_SPEED_HIGH) {
+               /* split */
+               ptd->dw5 = __constant_cpu_to_le32(0x1c);
+
+               if (qh->period >= 32)
+                       period = qh->period / 2;
+               else
+                       period = qh->period;
+
+       } else {
+
+               if (qh->period >= 8)
+                       period = qh->period/8;
+               else
+                       period = qh->period;
+
+               if (period >= 32)
+                       period  = 16;
+
+               if (qh->period >= 8) {
+                       /* millisecond period */
+                       period = (period << 3);
+               } else {
+                       /* usof based tranmsfers */
+                       /* minimum 4 usofs */
+                       usof = 0x11;
+               }
+       }
+
+       ptd->dw2 |= cpu_to_le32(period);
+       ptd->dw4 = cpu_to_le32(usof);
+}
+
+static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+                       struct isp1760_qtd *qtd, struct urb *urb,
+                       u32 payload, struct ptd *ptd)
+{
+       transform_into_atl(priv, qh, qtd, urb, payload, ptd);
+       transform_add_int(priv, qh, qtd, urb,  payload, ptd);
+}
+
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len,
+               u32 token)
+{
+       int count;
+
+       qtd->data_buffer = databuffer;
+       qtd->packet_type = GET_QTD_TOKEN_TYPE(token);
+       qtd->toggle = GET_DATA_TOGGLE(token);
+
+       if (len > HC_ATL_PL_SIZE)
+               count = HC_ATL_PL_SIZE;
+       else
+               count = len;
+
+       qtd->length = count;
+       return count;
+}
+
+static int check_error(struct ptd *ptd)
+{
+       int error = 0;
+       u32 dw3;
+
+       dw3 = le32_to_cpu(ptd->dw3);
+       if (dw3 & DW3_HALT_BIT)
+               error = -EPIPE;
+
+       if (dw3 & DW3_ERROR_BIT) {
+               printk(KERN_ERR "error bit is set in DW3\n");
+               error = -EPIPE;
+       }
+
+       if (dw3 & DW3_QTD_ACTIVE) {
+               printk(KERN_ERR "transfer active bit is set DW3\n");
+               printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf,
+                               (le32_to_cpu(ptd->dw2) >> 25) & 0xf);
+       }
+
+       return error;
+}
+
+static void check_int_err_status(u32 dw4)
+{
+       u32 i;
+
+       dw4 >>= 8;
+
+       for (i = 0; i < 8; i++) {
+               switch (dw4 & 0x7) {
+               case INT_UNDERRUN:
+                       printk(KERN_ERR "ERROR: under run , %d\n", i);
+                       break;
+
+               case INT_EXACT:
+                       printk(KERN_ERR "ERROR: transaction error, %d\n", i);
+                       break;
+
+               case INT_BABBLE:
+                       printk(KERN_ERR "ERROR: babble error, %d\n", i);
+                       break;
+               }
+               dw4 >>= 3;
+       }
+}
+
+static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv,
+               u32 payload)
+{
+       u32 token;
+       struct usb_hcd *hcd = priv_to_hcd(priv);
+
+       token = qtd->packet_type;
+
+       if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) {
+               switch (token) {
+               case IN_PID:
+                       break;
+               case OUT_PID:
+               case SETUP_PID:
+                       priv_write_copy(priv, qtd->data_buffer,
+                                       hcd->regs + payload,
+                                       qtd->length);
+               }
+       }
+}
+
+static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload,
+               struct isp1760_hcd *priv, struct isp1760_qh *qh,
+               struct urb *urb, u32 slot, struct isp1760_qtd *qtd)
+{
+       struct ptd ptd;
+       struct usb_hcd *hcd = priv_to_hcd(priv);
+
+       transform_into_atl(priv, qh, qtd, urb, payload, &ptd);
+       priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd));
+       enqueue_one_qtd(qtd, priv, payload);
+
+       priv->atl_ints[slot].urb = urb;
+       priv->atl_ints[slot].qh = qh;
+       priv->atl_ints[slot].qtd = qtd;
+       priv->atl_ints[slot].data_buffer = qtd->data_buffer;
+       priv->atl_ints[slot].payload = payload;
+       qtd->status |= URB_ENQUEUED | URB_TYPE_ATL;
+       qtd->status |= slot << 16;
+}
+
+static void enqueue_one_int_qtd(u32 int_regs, u32 payload,
+               struct isp1760_hcd *priv, struct isp1760_qh *qh,
+               struct urb *urb, u32 slot,  struct isp1760_qtd *qtd)
+{
+       struct ptd ptd;
+       struct usb_hcd *hcd = priv_to_hcd(priv);
+
+       transform_into_int(priv, qh, qtd, urb, payload, &ptd);
+       priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd));
+       enqueue_one_qtd(qtd, priv, payload);
+
+       priv->int_ints[slot].urb = urb;
+       priv->int_ints[slot].qh = qh;
+       priv->int_ints[slot].qtd = qtd;
+       priv->int_ints[slot].data_buffer = qtd->data_buffer;
+       priv->int_ints[slot].payload = payload;
+       qtd->status |= URB_ENQUEUED | URB_TYPE_INT;
+       qtd->status |= slot << 16;
+}
+
+void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+               struct isp1760_qtd *qtd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       u32 skip_map, or_map;
+       u32 queue_entry;
+       u32 slot;
+       u32 atl_regs, payload;
+       u32 buffstatus;
+
+       skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+       BUG_ON(!skip_map);
+       slot = __ffs(skip_map);
+       queue_entry = 1 << slot;
+
+       atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd);
+
+       payload = alloc_mem(priv, qtd->length);
+
+       enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+       or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+       or_map |= queue_entry;
+       isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+       skip_map &= ~queue_entry;
+       isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+       buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+       buffstatus |= ATL_BUFFER;
+       isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+               struct isp1760_qtd *qtd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       u32 skip_map, or_map;
+       u32 queue_entry;
+       u32 slot;
+       u32 int_regs, payload;
+       u32 buffstatus;
+
+       skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+       BUG_ON(!skip_map);
+       slot = __ffs(skip_map);
+       queue_entry = 1 << slot;
+
+       int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd);
+
+       payload = alloc_mem(priv, qtd->length);
+
+       enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+       or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+       or_map |= queue_entry;
+       isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+       skip_map &= ~queue_entry;
+       isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+       buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+       buffstatus |= INT_BUFFER;
+       isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status)
+__releases(priv->lock)
+__acquires(priv->lock)
+{
+       if (!urb->unlinked) {
+               if (status == -EINPROGRESS)
+                       status = 0;
+       }
+
+       /* complete() can reenter this HCD */
+       usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+       spin_unlock(&priv->lock);
+       usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status);
+       spin_lock(&priv->lock);
+}
+
+static void isp1760_qtd_free(struct isp1760_qtd *qtd)
+{
+       kmem_cache_free(qtd_cachep, qtd);
+}
+
+static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd)
+{
+       struct isp1760_qtd *tmp_qtd;
+
+       tmp_qtd = qtd->hw_next;
+       list_del(&qtd->qtd_list);
+       isp1760_qtd_free(qtd);
+       return tmp_qtd;
+}
+
+/*
+ * Remove this QTD from the QH list and free its memory. If this QTD
+ * isn't the last one than remove also his successor(s).
+ * Returns the QTD which is part of an new URB and should be enqueued.
+ */
+static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd)
+{
+       struct isp1760_qtd *tmp_qtd;
+       int last_one;
+
+       do {
+               tmp_qtd = qtd->hw_next;
+               last_one = qtd->status & URB_COMPLETE_NOTIFY;
+               list_del(&qtd->qtd_list);
+               isp1760_qtd_free(qtd);
+               qtd = tmp_qtd;
+       } while (!last_one && qtd);
+
+       return qtd;
+}
+
+static void do_atl_int(struct usb_hcd *usb_hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+       u32 done_map, skip_map;
+       struct ptd ptd;
+       struct urb *urb = NULL;
+       u32 atl_regs_base;
+       u32 atl_regs;
+       u32 queue_entry;
+       u32 payload;
+       u32 length;
+       u32 or_map;
+       u32 status = -EINVAL;
+       int error;
+       struct isp1760_qtd *qtd;
+       struct isp1760_qh *qh;
+       u32 rl;
+       u32 nakcount;
+
+       done_map = isp1760_readl(usb_hcd->regs +
+                       HC_ATL_PTD_DONEMAP_REG);
+       skip_map = isp1760_readl(usb_hcd->regs +
+                       HC_ATL_PTD_SKIPMAP_REG);
+
+       or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+       or_map &= ~done_map;
+       isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+       atl_regs_base = ATL_REGS_OFFSET;
+       while (done_map) {
+               u32 dw1;
+               u32 dw2;
+               u32 dw3;
+
+               status = 0;
+
+               queue_entry = __ffs(done_map);
+               done_map &= ~(1 << queue_entry);
+               skip_map |= 1 << queue_entry;
+
+               atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd);
+
+               urb = priv->atl_ints[queue_entry].urb;
+               qtd = priv->atl_ints[queue_entry].qtd;
+               qh = priv->atl_ints[queue_entry].qh;
+               payload = priv->atl_ints[queue_entry].payload;
+
+               if (!qh) {
+                       printk(KERN_ERR "qh is 0\n");
+                       continue;
+               }
+               priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs,
+                               atl_regs, sizeof(ptd));
+
+               dw1 = le32_to_cpu(ptd.dw1);
+               dw2 = le32_to_cpu(ptd.dw2);
+               dw3 = le32_to_cpu(ptd.dw3);
+               rl = (dw2 >> 25) & 0x0f;
+               nakcount = (dw3 >> 19) & 0xf;
+
+               /* Transfer Error, *but* active and no HALT -> reload */
+               if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) &&
+                               !(dw3 & DW3_HALT_BIT)) {
+
+                       /* according to ppriv code, we have to
+                        * reload this one if trasfered bytes != requested bytes
+                        * else act like everything went smooth..
+                        * XXX This just doesn't feel right and hasn't
+                        * triggered so far.
+                        */
+
+                       length = PTD_XFERRED_LENGTH(dw3);
+                       printk(KERN_ERR "Should reload now.... transfered %d "
+                                       "of %zu\n", length, qtd->length);
+                       BUG();
+               }
+
+               if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) {
+                       u32 buffstatus;
+
+                       /* XXX
+                        * NAKs are handled in HW by the chip. Usually if the
+                        * device is not able to send data fast enough.
+                        * This did not trigger for a long time now.
+                        */
+                       printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: "
+                                       "%d of %d done: %08x cur: %08x\n", qtd,
+                                       urb, qh, PTD_XFERRED_LENGTH(dw3),
+                                       qtd->length, done_map,
+                                       (1 << queue_entry));
+
+                       /* RL counter = ERR counter */
+                       dw3 &= ~(0xf << 19);
+                       dw3 |= rl << 19;
+                       dw3 &= ~(3 << (55 - 32));
+                       dw3 |= ERR_COUNTER << (55 - 32);
+
+                       /*
+                        * It is not needed to write skip map back because it
+                        * is unchanged. Just make sure that this entry is
+                        * unskipped once it gets written to the HW.
+                        */
+                       skip_map &= ~(1 << queue_entry);
+                       or_map = isp1760_readl(usb_hcd->regs +
+                                       HC_ATL_IRQ_MASK_OR_REG);
+                       or_map |= 1 << queue_entry;
+                       isp1760_writel(or_map, usb_hcd->regs +
+                                       HC_ATL_IRQ_MASK_OR_REG);
+
+                       ptd.dw3 = cpu_to_le32(dw3);
+                       priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+                                       atl_regs, sizeof(ptd));
+
+                       ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID);
+                       priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+                                       atl_regs, sizeof(ptd));
+
+                       buffstatus = isp1760_readl(usb_hcd->regs +
+                                       HC_BUFFER_STATUS_REG);
+                       buffstatus |= ATL_BUFFER;
+                       isp1760_writel(buffstatus, usb_hcd->regs +
+                                       HC_BUFFER_STATUS_REG);
+                       continue;
+               }
+
+               error = check_error(&ptd);
+               if (error) {
+                       status = error;
+                       priv->atl_ints[queue_entry].qh->toggle = 0;
+                       priv->atl_ints[queue_entry].qh->ping = 0;
+                       urb->status = -EPIPE;
+
+#if 0
+                       printk(KERN_ERR "Error in %s().\n", __func__);
+                       printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+                                       "dw3: %08x dw4: %08x dw5: %08x dw6: "
+                                       "%08x dw7: %08x\n",
+                                       ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+                                       ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+               } else {
+                       if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+                               priv->atl_ints[queue_entry].qh->toggle = dw3 &
+                                       (1 << 25);
+                               priv->atl_ints[queue_entry].qh->ping = dw3 &
+                                       (1 << 26);
+                       }
+               }
+
+               length = PTD_XFERRED_LENGTH(dw3);
+               if (length) {
+                       switch (DW1_GET_PID(dw1)) {
+                       case IN_PID:
+                               priv_read_copy(priv,
+                                       priv->atl_ints[queue_entry].data_buffer,
+                                       usb_hcd->regs + payload, payload,
+                                       length);
+
+                       case OUT_PID:
+
+                               urb->actual_length += length;
+
+                       case SETUP_PID:
+                               break;
+                       }
+               }
+
+               priv->atl_ints[queue_entry].data_buffer = NULL;
+               priv->atl_ints[queue_entry].urb = NULL;
+               priv->atl_ints[queue_entry].qtd = NULL;
+               priv->atl_ints[queue_entry].qh = NULL;
+
+               free_mem(priv, payload);
+
+               isp1760_writel(skip_map, usb_hcd->regs +
+                               HC_ATL_PTD_SKIPMAP_REG);
+
+               if (urb->status == -EPIPE) {
+                       /* HALT was received */
+
+                       qtd = clean_up_qtdlist(qtd);
+                       isp1760_urb_done(priv, urb, urb->status);
+
+               } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) {
+                       /* short BULK received */
+
+                       printk(KERN_ERR "short bulk, %d instead %d\n", length,
+                                       qtd->length);
+                       if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+                               urb->status = -EREMOTEIO;
+                               printk(KERN_ERR "not okey\n");
+                       }
+
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = 0;
+
+                       qtd = clean_up_qtdlist(qtd);
+
+                       isp1760_urb_done(priv, urb, urb->status);
+
+               } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+                       /* that was the last qtd of that URB */
+
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = 0;
+
+                       qtd = clean_this_qtd(qtd);
+                       isp1760_urb_done(priv, urb, urb->status);
+
+               } else {
+                       /* next QTD of this URB */
+
+                       qtd = clean_this_qtd(qtd);
+                       BUG_ON(!qtd);
+               }
+
+               if (qtd)
+                       enqueue_an_ATL_packet(usb_hcd, qh, qtd);
+
+               skip_map = isp1760_readl(usb_hcd->regs +
+                               HC_ATL_PTD_SKIPMAP_REG);
+       }
+}
+
+static void do_intl_int(struct usb_hcd *usb_hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+       u32 done_map, skip_map;
+       struct ptd ptd;
+       struct urb *urb = NULL;
+       u32 int_regs;
+       u32 int_regs_base;
+       u32 payload;
+       u32 length;
+       u32 or_map;
+       int error;
+       u32 queue_entry;
+       struct isp1760_qtd *qtd;
+       struct isp1760_qh *qh;
+
+       done_map = isp1760_readl(usb_hcd->regs +
+                       HC_INT_PTD_DONEMAP_REG);
+       skip_map = isp1760_readl(usb_hcd->regs +
+                       HC_INT_PTD_SKIPMAP_REG);
+
+       or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+       or_map &= ~done_map;
+       isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+       int_regs_base = INT_REGS_OFFSET;
+
+       while (done_map) {
+               u32 dw1;
+               u32 dw3;
+
+               queue_entry = __ffs(done_map);
+               done_map &= ~(1 << queue_entry);
+               skip_map |= 1 << queue_entry;
+
+               int_regs = int_regs_base + queue_entry * sizeof(struct ptd);
+               urb = priv->int_ints[queue_entry].urb;
+               qtd = priv->int_ints[queue_entry].qtd;
+               qh = priv->int_ints[queue_entry].qh;
+               payload = priv->int_ints[queue_entry].payload;
+
+               if (!qh) {
+                       printk(KERN_ERR "(INT) qh is 0\n");
+                       continue;
+               }
+
+               priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs,
+                               int_regs, sizeof(ptd));
+               dw1 = le32_to_cpu(ptd.dw1);
+               dw3 = le32_to_cpu(ptd.dw3);
+               check_int_err_status(le32_to_cpu(ptd.dw4));
+
+               error = check_error(&ptd);
+               if (error) {
+#if 0
+                       printk(KERN_ERR "Error in %s().\n", __func__);
+                       printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+                                       "dw3: %08x dw4: %08x dw5: %08x dw6: "
+                                       "%08x dw7: %08x\n",
+                                       ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+                                       ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+                       urb->status = -EPIPE;
+                       priv->int_ints[queue_entry].qh->toggle = 0;
+                       priv->int_ints[queue_entry].qh->ping = 0;
+
+               } else {
+                       priv->int_ints[queue_entry].qh->toggle =
+                               dw3 & (1 << 25);
+                       priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26);
+               }
+
+               if (urb->dev->speed != USB_SPEED_HIGH)
+                       length = PTD_XFERRED_LENGTH_LO(dw3);
+               else
+                       length = PTD_XFERRED_LENGTH(dw3);
+
+               if (length) {
+                       switch (DW1_GET_PID(dw1)) {
+                       case IN_PID:
+                               priv_read_copy(priv,
+                                       priv->int_ints[queue_entry].data_buffer,
+                                       usb_hcd->regs + payload , payload,
+                                       length);
+                       case OUT_PID:
+
+                               urb->actual_length += length;
+
+                       case SETUP_PID:
+                               break;
+                       }
+               }
+
+               priv->int_ints[queue_entry].data_buffer = NULL;
+               priv->int_ints[queue_entry].urb = NULL;
+               priv->int_ints[queue_entry].qtd = NULL;
+               priv->int_ints[queue_entry].qh = NULL;
+
+               isp1760_writel(skip_map, usb_hcd->regs +
+                               HC_INT_PTD_SKIPMAP_REG);
+               free_mem(priv, payload);
+
+               if (urb->status == -EPIPE) {
+                       /* HALT received */
+
+                        qtd = clean_up_qtdlist(qtd);
+                        isp1760_urb_done(priv, urb, urb->status);
+
+               } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = 0;
+
+                       qtd = clean_this_qtd(qtd);
+                       isp1760_urb_done(priv, urb, urb->status);
+
+               } else {
+                       /* next QTD of this URB */
+
+                       qtd = clean_this_qtd(qtd);
+                       BUG_ON(!qtd);
+               }
+
+               if (qtd)
+                       enqueue_an_INT_packet(usb_hcd, qh, qtd);
+
+               skip_map = isp1760_readl(usb_hcd->regs +
+                               HC_INT_PTD_SKIPMAP_REG);
+       }
+}
+
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb,
+               gfp_t flags)
+{
+       struct isp1760_qh *qh;
+       int is_input, type;
+
+       qh = isp1760_qh_alloc(priv, flags);
+       if (!qh)
+               return qh;
+
+       /*
+        * init endpoint/device data for this QH
+        */
+       is_input = usb_pipein(urb->pipe);
+       type = usb_pipetype(urb->pipe);
+
+       if (type == PIPE_INTERRUPT) {
+
+               if (urb->dev->speed == USB_SPEED_HIGH) {
+
+                       qh->period = urb->interval >> 3;
+                       if (qh->period == 0 && urb->interval != 1) {
+                               /* NOTE interval 2 or 4 uframes could work.
+                                * But interval 1 scheduling is simpler, and
+                                * includes high bandwidth.
+                                */
+                               printk(KERN_ERR "intr period %d uframes, NYET!",
+                                               urb->interval);
+                               qh_destroy(qh);
+                               return NULL;
+                       }
+               } else {
+                       qh->period = urb->interval;
+               }
+       }
+
+       /* support for tt scheduling, and access to toggles */
+       qh->dev = urb->dev;
+
+       if (!usb_pipecontrol(urb->pipe))
+               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
+                               1);
+       return qh;
+}
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv,
+               struct urb *urb, struct list_head *qtd_list, int epnum,
+               void **ptr)
+{
+       struct isp1760_qh *qh;
+       struct isp1760_qtd *qtd;
+       struct isp1760_qtd *prev_qtd;
+
+       qh = (struct isp1760_qh *)*ptr;
+       if (!qh) {
+               /* can't sleep here, we have priv->lock... */
+               qh = qh_make(priv, urb, GFP_ATOMIC);
+               if (!qh)
+                       return qh;
+               *ptr = qh;
+       }
+
+       qtd = list_entry(qtd_list->next, struct isp1760_qtd,
+                       qtd_list);
+       if (!list_empty(&qh->qtd_list))
+               prev_qtd = list_entry(qh->qtd_list.prev,
+                               struct isp1760_qtd, qtd_list);
+       else
+               prev_qtd = NULL;
+
+       list_splice(qtd_list, qh->qtd_list.prev);
+       if (prev_qtd) {
+               BUG_ON(prev_qtd->hw_next);
+               prev_qtd->hw_next = qtd;
+       }
+
+       urb->hcpriv = qh;
+       return qh;
+}
+
+static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb,
+               struct list_head *qtd_list)
+{
+       struct list_head *entry, *temp;
+
+       list_for_each_safe(entry, temp, qtd_list) {
+               struct isp1760_qtd      *qtd;
+
+               qtd = list_entry(entry, struct isp1760_qtd, qtd_list);
+               list_del(&qtd->qtd_list);
+               isp1760_qtd_free(qtd);
+       }
+}
+
+static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb,
+               struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p)
+{
+       struct isp1760_qtd         *qtd;
+       int                     epnum;
+       unsigned long           flags;
+       struct isp1760_qh          *qh = NULL;
+       int                     rc;
+       int qh_busy;
+
+       qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list);
+       epnum = urb->ep->desc.bEndpointAddress;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) {
+               rc = -ESHUTDOWN;
+               goto done;
+       }
+       rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb);
+       if (rc)
+               goto done;
+
+       qh = urb->ep->hcpriv;
+       if (qh)
+               qh_busy = !list_empty(&qh->qtd_list);
+       else
+               qh_busy = 0;
+
+       qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv);
+       if (!qh) {
+               usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+               rc = -ENOMEM;
+               goto done;
+       }
+
+       if (!qh_busy)
+               p(priv_to_hcd(priv), qh, qtd);
+
+done:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       if (!qh)
+               qtd_list_free(priv, urb, qtd_list);
+       return rc;
+}
+
+static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv,
+               gfp_t flags)
+{
+       struct isp1760_qtd *qtd;
+
+       qtd = kmem_cache_zalloc(qtd_cachep, flags);
+       if (qtd)
+               INIT_LIST_HEAD(&qtd->qtd_list);
+
+       return qtd;
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv,
+               struct urb *urb, struct list_head *head, gfp_t flags)
+{
+       struct isp1760_qtd *qtd, *qtd_prev;
+       void *buf;
+       int len, maxpacket;
+       int is_input;
+       u32 token;
+
+       /*
+        * URBs map to sequences of QTDs:  one logical transaction
+        */
+       qtd = isp1760_qtd_alloc(priv, flags);
+       if (!qtd)
+               return NULL;
+
+       list_add_tail(&qtd->qtd_list, head);
+       qtd->urb = urb;
+       urb->status = -EINPROGRESS;
+
+       token = 0;
+       /* for split transactions, SplitXState initialized to zero */
+
+       len = urb->transfer_buffer_length;
+       is_input = usb_pipein(urb->pipe);
+       if (usb_pipecontrol(urb->pipe)) {
+               /* SETUP pid */
+               qtd_fill(qtd, urb->setup_packet,
+                               sizeof(struct usb_ctrlrequest),
+                               token | SETUP_PID);
+
+               /* ... and always at least one more pid */
+               token ^= DATA_TOGGLE;
+               qtd_prev = qtd;
+               qtd = isp1760_qtd_alloc(priv, flags);
+               if (!qtd)
+                       goto cleanup;
+               qtd->urb = urb;
+               qtd_prev->hw_next = qtd;
+               list_add_tail(&qtd->qtd_list, head);
+
+               /* for zero length DATA stages, STATUS is always IN */
+               if (len == 0)
+                       token |= IN_PID;
+       }
+
+       /*
+        * data transfer stage:  buffer setup
+        */
+       buf = urb->transfer_buffer;
+
+       if (is_input)
+               token |= IN_PID;
+       else
+               token |= OUT_PID;
+
+       maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+       /*
+        * buffer gets wrapped in one or more qtds;
+        * last one may be "short" (including zero len)
+        * and may serve as a control status ack
+        */
+       for (;;) {
+               int this_qtd_len;
+
+               if (!buf && len) {
+                       /* XXX This looks like usb storage / SCSI bug */
+                       printk(KERN_ERR "buf is null, dma is %08lx len is %d\n",
+                                       (long unsigned)urb->transfer_dma, len);
+                       WARN_ON(1);
+               }
+
+               this_qtd_len = qtd_fill(qtd, buf, len, token);
+               len -= this_qtd_len;
+               buf += this_qtd_len;
+
+               /* qh makes control packets use qtd toggle; maybe switch it */
+               if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+                       token ^= DATA_TOGGLE;
+
+               if (len <= 0)
+                       break;
+
+               qtd_prev = qtd;
+               qtd = isp1760_qtd_alloc(priv, flags);
+               if (!qtd)
+                       goto cleanup;
+               qtd->urb = urb;
+               qtd_prev->hw_next = qtd;
+               list_add_tail(&qtd->qtd_list, head);
+       }
+
+       /*
+        * control requests may need a terminating data "status" ack;
+        * bulk ones may need a terminating short packet (zero length).
+        */
+       if (urb->transfer_buffer_length != 0) {
+               int one_more = 0;
+
+               if (usb_pipecontrol(urb->pipe)) {
+                       one_more = 1;
+                       /* "in" <--> "out"  */
+                       token ^= IN_PID;
+                       /* force DATA1 */
+                       token |= DATA_TOGGLE;
+               } else if (usb_pipebulk(urb->pipe)
+                               && (urb->transfer_flags & URB_ZERO_PACKET)
+                               && !(urb->transfer_buffer_length % maxpacket)) {
+                       one_more = 1;
+               }
+               if (one_more) {
+                       qtd_prev = qtd;
+                       qtd = isp1760_qtd_alloc(priv, flags);
+                       if (!qtd)
+                               goto cleanup;
+                       qtd->urb = urb;
+                       qtd_prev->hw_next = qtd;
+                       list_add_tail(&qtd->qtd_list, head);
+
+                       /* never any data in such packets */
+                       qtd_fill(qtd, NULL, 0, token);
+               }
+       }
+
+       qtd->status = URB_COMPLETE_NOTIFY;
+       return head;
+
+cleanup:
+       qtd_list_free(priv, urb, head);
+       return NULL;
+}
+
+static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+               gfp_t mem_flags)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       struct list_head qtd_list;
+       packet_enqueue *pe;
+
+       INIT_LIST_HEAD(&qtd_list);
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+
+               if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+                       return -ENOMEM;
+               pe =  enqueue_an_ATL_packet;
+               break;
+
+       case PIPE_INTERRUPT:
+               if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+                       return -ENOMEM;
+               pe = enqueue_an_INT_packet;
+               break;
+
+       case PIPE_ISOCHRONOUS:
+               printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n");
+       default:
+               return -EPIPE;
+       }
+
+       isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe);
+       return 0;
+}
+
+static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+               int status)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       struct inter_packet_info *ints;
+       u32 i;
+       u32 reg_base, or_reg, skip_reg;
+       int flags;
+       struct ptd ptd;
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_ISOCHRONOUS:
+               return -EPIPE;
+               break;
+
+       case PIPE_INTERRUPT:
+               ints = priv->int_ints;
+               reg_base = INT_REGS_OFFSET;
+               or_reg = HC_INT_IRQ_MASK_OR_REG;
+               skip_reg = HC_INT_PTD_SKIPMAP_REG;
+               break;
+
+       default:
+               ints = priv->atl_ints;
+               reg_base = ATL_REGS_OFFSET;
+               or_reg = HC_ATL_IRQ_MASK_OR_REG;
+               skip_reg = HC_ATL_PTD_SKIPMAP_REG;
+               break;
+       }
+
+       memset(&ptd, 0, sizeof(ptd));
+       spin_lock_irqsave(&priv->lock, flags);
+
+       for (i = 0; i < 32; i++) {
+               if (ints->urb == urb) {
+                       u32 skip_map;
+                       u32 or_map;
+                       struct isp1760_qtd *qtd;
+
+                       skip_map = isp1760_readl(hcd->regs + skip_reg);
+                       skip_map |= 1 << i;
+                       isp1760_writel(skip_map, hcd->regs + skip_reg);
+
+                       or_map = isp1760_readl(hcd->regs + or_reg);
+                       or_map &= ~(1 << i);
+                       isp1760_writel(or_map, hcd->regs + or_reg);
+
+                       priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base
+                                       + i * sizeof(ptd), sizeof(ptd));
+                       qtd = ints->qtd;
+
+                       clean_up_qtdlist(qtd);
+
+                       free_mem(priv, ints->payload);
+
+                       ints->urb = NULL;
+                       ints->qh = NULL;
+                       ints->qtd = NULL;
+                       ints->data_buffer = NULL;
+                       ints->payload = 0;
+
+                       isp1760_urb_done(priv, urb, status);
+                       break;
+               }
+               ints++;
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 0;
+}
+
+static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+       u32 imask;
+       irqreturn_t irqret = IRQ_NONE;
+
+       spin_lock(&priv->lock);
+
+       if (!(usb_hcd->state & HC_STATE_RUNNING))
+               goto leave;
+
+       imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG);
+       if (unlikely(!imask))
+               goto leave;
+
+       isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG);
+       if (imask & HC_ATL_INT)
+               do_atl_int(usb_hcd);
+
+       if (imask & HC_INTL_INT)
+               do_intl_int(usb_hcd);
+
+       irqret = IRQ_HANDLED;
+leave:
+       spin_unlock(&priv->lock);
+       return irqret;
+}
+
+static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       u32 temp, status = 0;
+       u32 mask;
+       int retval = 1;
+       unsigned long flags;
+
+       /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+       if (!HC_IS_RUNNING(hcd->state))
+               return 0;
+
+       /* init status to no-changes */
+       buf[0] = 0;
+       mask = PORT_CSC;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       temp = isp1760_readl(hcd->regs + HC_PORTSC1);
+
+       if (temp & PORT_OWNER) {
+               if (temp & PORT_CSC) {
+                       temp &= ~PORT_CSC;
+                       isp1760_writel(temp, hcd->regs + HC_PORTSC1);
+                       goto done;
+               }
+       }
+
+       /*
+        * Return status information even for ports with OWNER set.
+        * Otherwise khubd wouldn't see the disconnect event when a
+        * high-speed device is switched over to the companion
+        * controller by the user.
+        */
+
+       if ((temp & mask) != 0
+                       || ((temp & PORT_RESUME) != 0
+                               && time_after_eq(jiffies,
+                                       priv->reset_done))) {
+               buf [0] |= 1 << (0 + 1);
+               status = STS_PCD;
+       }
+       /* FIXME autosuspend idle root hubs */
+done:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return status ? retval : 0;
+}
+
+static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+               struct usb_hub_descriptor *desc)
+{
+       int ports = HCS_N_PORTS(priv->hcs_params);
+       u16 temp;
+
+       desc->bDescriptorType = 0x29;
+       /* priv 1.0, 2.3.9 says 20ms max */
+       desc->bPwrOn2PwrGood = 10;
+       desc->bHubContrCurrent = 0;
+
+       desc->bNbrPorts = ports;
+       temp = 1 + (ports / 8);
+       desc->bDescLength = 7 + 2 * temp;
+
+       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+       memset(&desc->bitmap[0], 0, temp);
+       memset(&desc->bitmap[temp], 0xff, temp);
+
+       /* per-port overcurrent reporting */
+       temp = 0x0008;
+       if (HCS_PPC(priv->hcs_params))
+               /* per-port power control */
+               temp |= 0x0001;
+       else
+               /* no power switching */
+               temp |= 0x0002;
+       desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+#define        PORT_WAKE_BITS  (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int check_reset_complete(struct isp1760_hcd *priv, int index,
+               u32 __iomem *status_reg, int port_status)
+{
+       if (!(port_status & PORT_CONNECT))
+               return port_status;
+
+       /* if reset finished and it's still not enabled -- handoff */
+       if (!(port_status & PORT_PE)) {
+
+               printk(KERN_ERR "port %d full speed --> companion\n",
+                       index + 1);
+
+               port_status |= PORT_OWNER;
+               port_status &= ~PORT_RWC_BITS;
+               isp1760_writel(port_status, status_reg);
+
+       } else
+               printk(KERN_ERR "port %d high speed\n", index + 1);
+
+       return port_status;
+}
+
+static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+               u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       int ports = HCS_N_PORTS(priv->hcs_params);
+       u32 __iomem *status_reg = hcd->regs + HC_PORTSC1;
+       u32 temp, status;
+       unsigned long flags;
+       int retval = 0;
+       unsigned selector;
+
+       /*
+        * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+        * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+        * (track current state ourselves) ... blink for diagnostics,
+        * power, "this is the one", etc.  EHCI spec supports this.
+        */
+
+       spin_lock_irqsave(&priv->lock, flags);
+       switch (typeReq) {
+       case ClearHubFeature:
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* no hub-wide feature/status flags */
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case ClearPortFeature:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               temp = isp1760_readl(status_reg);
+
+               /*
+                * Even if OWNER is set, so the port is owned by the
+                * companion controller, khubd needs to be able to clear
+                * the port-change status bits (especially
+                * USB_PORT_FEAT_C_CONNECTION).
+                */
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       isp1760_writel(temp & ~PORT_PE, status_reg);
+                       break;
+               case USB_PORT_FEAT_C_ENABLE:
+                       /* XXX error? */
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       if (temp & PORT_RESET)
+                               goto error;
+
+                       if (temp & PORT_SUSPEND) {
+                               if ((temp & PORT_PE) == 0)
+                                       goto error;
+                               /* resume signaling for 20 msec */
+                               temp &= ~(PORT_RWC_BITS);
+                               isp1760_writel(temp | PORT_RESUME,
+                                               status_reg);
+                               priv->reset_done = jiffies +
+                                       msecs_to_jiffies(20);
+                       }
+                       break;
+               case USB_PORT_FEAT_C_SUSPEND:
+                       /* we auto-clear this feature */
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       if (HCS_PPC(priv->hcs_params))
+                               isp1760_writel(temp & ~PORT_POWER, status_reg);
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+                       isp1760_writel(temp | PORT_CSC,
+                                       status_reg);
+                       break;
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       /* XXX error ?*/
+                       break;
+               case USB_PORT_FEAT_C_RESET:
+                       /* GetPortStatus clears reset */
+                       break;
+               default:
+                       goto error;
+               }
+               isp1760_readl(hcd->regs + HC_USBCMD);
+               break;
+       case GetHubDescriptor:
+               isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+                       buf);
+               break;
+       case GetHubStatus:
+               /* no hub-wide feature/status flags */
+               memset(buf, 0, 4);
+               break;
+       case GetPortStatus:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               status = 0;
+               temp = isp1760_readl(status_reg);
+
+               /* wPortChange bits */
+               if (temp & PORT_CSC)
+                       status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+
+
+               /* whoever resumes must GetPortStatus to complete it!! */
+               if (temp & PORT_RESUME) {
+                       printk(KERN_ERR "Port resume should be skipped.\n");
+
+                       /* Remote Wakeup received? */
+                       if (!priv->reset_done) {
+                               /* resume signaling for 20 msec */
+                               priv->reset_done = jiffies
+                                               + msecs_to_jiffies(20);
+                               /* check the port again */
+                               mod_timer(&priv_to_hcd(priv)->rh_timer,
+                                               priv->reset_done);
+                       }
+
+                       /* resume completed? */
+                       else if (time_after_eq(jiffies,
+                                       priv->reset_done)) {
+                               status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+                               priv->reset_done = 0;
+
+                               /* stop resume signaling */
+                               temp = isp1760_readl(status_reg);
+                               isp1760_writel(
+                                       temp & ~(PORT_RWC_BITS | PORT_RESUME),
+                                       status_reg);
+                               retval = handshake(priv, status_reg,
+                                          PORT_RESUME, 0, 2000 /* 2msec */);
+                               if (retval != 0) {
+                                       isp1760_err(priv,
+                                               "port %d resume error %d\n",
+                                               wIndex + 1, retval);
+                                       goto error;
+                               }
+                               temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+                       }
+               }
+
+               /* whoever resets must GetPortStatus to complete it!! */
+               if ((temp & PORT_RESET)
+                               && time_after_eq(jiffies,
+                                       priv->reset_done)) {
+                       status |= 1 << USB_PORT_FEAT_C_RESET;
+                       priv->reset_done = 0;
+
+                       /* force reset to complete */
+                       isp1760_writel(temp & ~PORT_RESET,
+                                       status_reg);
+                       /* REVISIT:  some hardware needs 550+ usec to clear
+                        * this bit; seems too long to spin routinely...
+                        */
+                       retval = handshake(priv, status_reg,
+                                       PORT_RESET, 0, 750);
+                       if (retval != 0) {
+                               isp1760_err(priv, "port %d reset error %d\n",
+                                               wIndex + 1, retval);
+                               goto error;
+                       }
+
+                       /* see what we found out */
+                       temp = check_reset_complete(priv, wIndex, status_reg,
+                                       isp1760_readl(status_reg));
+               }
+               /*
+                * Even if OWNER is set, there's no harm letting khubd
+                * see the wPortStatus values (they should all be 0 except
+                * for PORT_POWER anyway).
+                */
+
+               if (temp & PORT_OWNER)
+                       printk(KERN_ERR "Warning: PORT_OWNER is set\n");
+
+               if (temp & PORT_CONNECT) {
+                       status |= 1 << USB_PORT_FEAT_CONNECTION;
+                       /* status may be from integrated TT */
+                       status |= ehci_port_speed(priv, temp);
+               }
+               if (temp & PORT_PE)
+                       status |= 1 << USB_PORT_FEAT_ENABLE;
+               if (temp & (PORT_SUSPEND|PORT_RESUME))
+                       status |= 1 << USB_PORT_FEAT_SUSPEND;
+               if (temp & PORT_RESET)
+                       status |= 1 << USB_PORT_FEAT_RESET;
+               if (temp & PORT_POWER)
+                       status |= 1 << USB_PORT_FEAT_POWER;
+
+               put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+               break;
+       case SetHubFeature:
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* no hub-wide feature/status flags */
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case SetPortFeature:
+               selector = wIndex >> 8;
+               wIndex &= 0xff;
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               temp = isp1760_readl(status_reg);
+               if (temp & PORT_OWNER)
+                       break;
+
+/*             temp &= ~PORT_RWC_BITS; */
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       isp1760_writel(temp | PORT_PE, status_reg);
+                       break;
+
+               case USB_PORT_FEAT_SUSPEND:
+                       if ((temp & PORT_PE) == 0
+                                       || (temp & PORT_RESET) != 0)
+                               goto error;
+
+                       isp1760_writel(temp | PORT_SUSPEND, status_reg);
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       if (HCS_PPC(priv->hcs_params))
+                               isp1760_writel(temp | PORT_POWER,
+                                               status_reg);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       if (temp & PORT_RESUME)
+                               goto error;
+                       /* line status bits may report this as low speed,
+                        * which can be fine if this root hub has a
+                        * transaction translator built in.
+                        */
+                       if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+                                       && PORT_USB11(temp)) {
+                               temp |= PORT_OWNER;
+                       } else {
+                               temp |= PORT_RESET;
+                               temp &= ~PORT_PE;
+
+                               /*
+                                * caller must wait, then call GetPortStatus
+                                * usb 2.0 spec says 50 ms resets on root
+                                */
+                               priv->reset_done = jiffies +
+                                       msecs_to_jiffies(50);
+                       }
+                       isp1760_writel(temp, status_reg);
+                       break;
+               default:
+                       goto error;
+               }
+               isp1760_readl(hcd->regs + HC_USBCMD);
+               break;
+
+       default:
+error:
+               /* "stall" on error */
+               retval = -EPIPE;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return retval;
+}
+
+static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd,
+               struct usb_host_endpoint *ep)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+       struct isp1760_qh *qh;
+       struct isp1760_qtd *qtd;
+       u32 flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       qh = ep->hcpriv;
+       if (!qh)
+               goto out;
+
+       ep->hcpriv = NULL;
+       do {
+               /* more than entry might get removed */
+               if (list_empty(&qh->qtd_list))
+                       break;
+
+               qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd,
+                               qtd_list);
+
+               if (qtd->status & URB_ENQUEUED) {
+
+                       spin_unlock_irqrestore(&priv->lock, flags);
+                       isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET);
+                       spin_lock_irqsave(&priv->lock, flags);
+               } else {
+                       struct urb *urb;
+
+                       urb = qtd->urb;
+                       clean_up_qtdlist(qtd);
+                       isp1760_urb_done(priv, urb, -ECONNRESET);
+               }
+       } while (1);
+
+       qh_destroy(qh);
+       /* remove requests and leak them.
+        * ATL are pretty fast done, INT could take a while...
+        * The latter shoule be removed
+        */
+out:
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int isp1760_get_frame(struct usb_hcd *hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       u32 fr;
+
+       fr = isp1760_readl(hcd->regs + HC_FRINDEX);
+       return (fr >> 3) % priv->periodic_size;
+}
+
+static void isp1760_stop(struct usb_hcd *hcd)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+       isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
+                       NULL, 0);
+       mdelay(20);
+
+       spin_lock_irq(&priv->lock);
+       ehci_reset(priv);
+       /* Disable IRQ */
+       isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+       spin_unlock_irq(&priv->lock);
+
+       isp1760_writel(0, hcd->regs + HC_CONFIGFLAG);
+}
+
+static void isp1760_shutdown(struct usb_hcd *hcd)
+{
+       u32 command;
+
+       isp1760_stop(hcd);
+       isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+
+       command = isp1760_readl(hcd->regs + HC_USBCMD);
+       command &= ~CMD_RUN;
+       isp1760_writel(command, hcd->regs + HC_USBCMD);
+}
+
+static const struct hc_driver isp1760_hc_driver = {
+       .description            = "isp1760-hcd",
+       .product_desc           = "NXP ISP1760 USB Host Controller",
+       .hcd_priv_size          = sizeof(struct isp1760_hcd),
+       .irq                    = isp1760_irq,
+       .flags                  = HCD_MEMORY | HCD_USB2,
+       .reset                  = isp1760_hc_setup,
+       .start                  = isp1760_run,
+       .stop                   = isp1760_stop,
+       .shutdown               = isp1760_shutdown,
+       .urb_enqueue            = isp1760_urb_enqueue,
+       .urb_dequeue            = isp1760_urb_dequeue,
+       .endpoint_disable       = isp1760_endpoint_disable,
+       .get_frame_number       = isp1760_get_frame,
+       .hub_status_data        = isp1760_hub_status_data,
+       .hub_control            = isp1760_hub_control,
+};
+
+int __init init_kmem_once(void)
+{
+       qtd_cachep = kmem_cache_create("isp1760_qtd",
+                       sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
+                       SLAB_MEM_SPREAD, NULL);
+
+       if (!qtd_cachep)
+               return -ENOMEM;
+
+       qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
+                       0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+
+       if (!qh_cachep) {
+               kmem_cache_destroy(qtd_cachep);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void deinit_kmem_cache(void)
+{
+       kmem_cache_destroy(qtd_cachep);
+       kmem_cache_destroy(qh_cachep);
+}
+
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+               u64 irqflags, struct device *dev, const char *busname)
+{
+       struct usb_hcd *hcd;
+       struct isp1760_hcd *priv;
+       int ret;
+
+       if (usb_disabled())
+               return ERR_PTR(-ENODEV);
+
+       /* prevent usb-core allocating DMA pages */
+       dev->dma_mask = NULL;
+
+       hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id);
+       if (!hcd)
+               return ERR_PTR(-ENOMEM);
+
+       priv = hcd_to_priv(hcd);
+       init_memory(priv);
+       hcd->regs = ioremap(res_start, res_len);
+       if (!hcd->regs) {
+               ret = -EIO;
+               goto err_put;
+       }
+
+       ret = usb_add_hcd(hcd, irq, irqflags);
+       if (ret)
+               goto err_unmap;
+
+       hcd->irq = irq;
+       hcd->rsrc_start = res_start;
+       hcd->rsrc_len = res_len;
+
+       return hcd;
+
+err_unmap:
+        iounmap(hcd->regs);
+
+err_put:
+        usb_put_hcd(hcd);
+
+        return ERR_PTR(ret);
+}
+
+MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
+MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
new file mode 100644 (file)
index 0000000..3d86d0f
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef _ISP1760_HCD_H_
+#define _ISP1760_HCD_H_
+
+/* exports for if */
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+               u64 irqflags, struct device *dev, const char *busname);
+int init_kmem_once(void);
+void deinit_kmem_cache(void);
+
+/* EHCI capability registers */
+#define HC_CAPLENGTH           0x00
+#define HC_HCSPARAMS           0x04
+#define HC_HCCPARAMS           0x08
+
+/* EHCI operational registers */
+#define HC_USBCMD              0x20
+#define HC_USBSTS              0x24
+#define HC_FRINDEX             0x2c
+#define HC_CONFIGFLAG          0x60
+#define HC_PORTSC1             0x64
+#define HC_ISO_PTD_DONEMAP_REG 0x130
+#define HC_ISO_PTD_SKIPMAP_REG 0x134
+#define HC_ISO_PTD_LASTPTD_REG 0x138
+#define HC_INT_PTD_DONEMAP_REG 0x140
+#define HC_INT_PTD_SKIPMAP_REG 0x144
+#define HC_INT_PTD_LASTPTD_REG 0x148
+#define HC_ATL_PTD_DONEMAP_REG 0x150
+#define HC_ATL_PTD_SKIPMAP_REG 0x154
+#define HC_ATL_PTD_LASTPTD_REG 0x158
+
+/* Configuration Register */
+#define HC_HW_MODE_CTRL                0x300
+#define ALL_ATX_RESET          (1 << 31)
+#define HW_DATA_BUS_32BIT      (1 << 8)
+#define HW_DACK_POL_HIGH       (1 << 6)
+#define HW_DREQ_POL_HIGH       (1 << 5)
+#define HW_INTR_HIGH_ACT       (1 << 2)
+#define HW_INTR_EDGE_TRIG      (1 << 1)
+#define HW_GLOBAL_INTR_EN      (1 << 0)
+
+#define HC_CHIP_ID_REG         0x304
+#define HC_SCRATCH_REG         0x308
+
+#define HC_RESET_REG           0x30c
+#define SW_RESET_RESET_HC      (1 << 1)
+#define SW_RESET_RESET_ALL     (1 << 0)
+
+#define HC_BUFFER_STATUS_REG   0x334
+#define ATL_BUFFER             0x1
+#define INT_BUFFER             0x2
+#define ISO_BUFFER             0x4
+#define BUFFER_MAP             0x7
+
+#define HC_MEMORY_REG          0x33c
+#define HC_PORT1_CTRL          0x374
+#define PORT1_POWER            (3 << 3)
+#define PORT1_INIT1            (1 << 7)
+#define PORT1_INIT2            (1 << 23)
+
+/* Interrupt Register */
+#define HC_INTERRUPT_REG       0x310
+
+#define HC_INTERRUPT_ENABLE    0x314
+#define INTERRUPT_ENABLE_MASK  (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
+#define FINAL_HW_CONFIG        (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT)
+
+#define HC_ISO_INT             (1 << 9)
+#define HC_ATL_INT             (1 << 8)
+#define HC_INTL_INT            (1 << 7)
+#define HC_EOT_INT             (1 << 3)
+#define HC_SOT_INT             (1 << 1)
+
+#define HC_ISO_IRQ_MASK_OR_REG 0x318
+#define HC_INT_IRQ_MASK_OR_REG 0x31C
+#define HC_ATL_IRQ_MASK_OR_REG 0x320
+#define HC_ISO_IRQ_MASK_AND_REG        0x324
+#define HC_INT_IRQ_MASK_AND_REG        0x328
+#define HC_ATL_IRQ_MASK_AND_REG        0x32C
+
+/* Register sets */
+#define HC_BEGIN_OF_ATL                0x0c00
+#define HC_BEGIN_OF_INT                0x0800
+#define HC_BEGIN_OF_ISO                0x0400
+#define HC_BEGIN_OF_PAYLOAD    0x1000
+
+/* urb state*/
+#define DELETE_URB             (0x0008)
+#define NO_TRANSFER_ACTIVE     (0xffffffff)
+
+#define ATL_REGS_OFFSET                (0xc00)
+#define INT_REGS_OFFSET                (0x800)
+
+/* Philips Transfer Descriptor (PTD) */
+struct ptd {
+       __le32 dw0;
+       __le32 dw1;
+       __le32 dw2;
+       __le32 dw3;
+       __le32 dw4;
+       __le32 dw5;
+       __le32 dw6;
+       __le32 dw7;
+};
+
+struct inter_packet_info {
+       void *data_buffer;
+       u32 payload;
+#define PTD_FIRE_NEXT          (1 << 0)
+#define PTD_URB_FINISHED       (1 << 1)
+       struct urb *urb;
+       struct isp1760_qh *qh;
+       struct isp1760_qtd *qtd;
+};
+
+
+typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
+               struct isp1760_qtd *qtd);
+
+#define isp1760_info(priv, fmt, args...) \
+       dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+#define isp1760_err(priv, fmt, args...) \
+       dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+/* chip memory management */
+struct memory_chunk {
+       unsigned int start;
+       unsigned int size;
+       unsigned int free;
+};
+
+/*
+ * 60kb divided in:
+ * - 32 blocks @ 256  bytes
+ * - 20 blocks @ 1024 bytes
+ * -  4 blocks @ 8192 bytes
+ */
+
+#define BLOCK_1_NUM 32
+#define BLOCK_2_NUM 20
+#define BLOCK_3_NUM 4
+
+#define BLOCK_1_SIZE 256
+#define BLOCK_2_SIZE 1024
+#define BLOCK_3_SIZE 8192
+#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+#define PAYLOAD_SIZE 0xf000
+
+/* I saw if some reloads if the pointer was negative */
+#define ISP1760_NULL_POINTER   (0x400)
+
+/* ATL */
+/* DW0 */
+#define PTD_VALID                      1
+#define PTD_LENGTH(x)                  (((u32) x) << 3)
+#define PTD_MAXPACKET(x)               (((u32) x) << 18)
+#define PTD_MULTI(x)                   (((u32) x) << 29)
+#define PTD_ENDPOINT(x)                        (((u32) x) << 31)
+/* DW1 */
+#define PTD_DEVICE_ADDR(x)             (((u32) x) << 3)
+#define PTD_PID_TOKEN(x)               (((u32) x) << 10)
+#define PTD_TRANS_BULK                 ((u32) 2 << 12)
+#define PTD_TRANS_INT                  ((u32) 3 << 12)
+#define PTD_TRANS_SPLIT                        ((u32) 1 << 14)
+#define PTD_SE_USB_LOSPEED             ((u32) 2 << 16)
+#define PTD_PORT_NUM(x)                        (((u32) x) << 18)
+#define PTD_HUB_NUM(x)                 (((u32) x) << 25)
+#define PTD_PING(x)                    (((u32) x) << 26)
+/* DW2 */
+#define PTD_RL_CNT(x)                  (((u32) x) << 25)
+#define PTD_DATA_START_ADDR(x)         (((u32) x) << 8)
+#define BASE_ADDR                      0x1000
+/* DW3 */
+#define PTD_CERR(x)                    (((u32) x) << 23)
+#define PTD_NAC_CNT(x)                 (((u32) x) << 19)
+#define PTD_ACTIVE                     ((u32) 1 << 31)
+#define PTD_DATA_TOGGLE(x)             (((u32) x) << 25)
+
+#define DW3_HALT_BIT                   (1 << 30)
+#define DW3_ERROR_BIT                  (1 << 28)
+#define DW3_QTD_ACTIVE                 (1 << 31)
+
+#define INT_UNDERRUN                   (1 << 2)
+#define INT_BABBLE                     (1 << 1)
+#define INT_EXACT                      (1 << 0)
+
+#define DW1_GET_PID(x)                 (((x) >> 10) & 0x3)
+#define PTD_XFERRED_LENGTH(x)          ((x) & 0x7fff)
+#define PTD_XFERRED_LENGTH_LO(x)       ((x) & 0x7ff)
+
+#define SETUP_PID      (2)
+#define IN_PID         (1)
+#define OUT_PID                (0)
+#define GET_QTD_TOKEN_TYPE(x)  ((x) & 0x3)
+
+#define DATA_TOGGLE            (1 << 31)
+#define GET_DATA_TOGGLE(x)     ((x) >> 31)
+
+/* Errata 1 */
+#define RL_COUNTER     (0)
+#define NAK_COUNTER    (0)
+#define ERR_COUNTER    (2)
+
+#define HC_ATL_PL_SIZE (8192)
+
+#endif
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
new file mode 100644 (file)
index 0000000..73fb2a3
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Glue code for the ISP1760 driver and bus
+ * Currently there is support for
+ * - OpenFirmware
+ * - PCI
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/io.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+#ifdef CONFIG_USB_ISP1760_OF
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_OF
+static int of_isp1760_probe(struct of_device *dev,
+               const struct of_device_id *match)
+{
+       struct usb_hcd *hcd;
+       struct device_node *dp = dev->node;
+       struct resource *res;
+       struct resource memory;
+       struct of_irq oirq;
+       int virq;
+       u64 res_len;
+       int ret;
+
+       ret = of_address_to_resource(dp, 0, &memory);
+       if (ret)
+               return -ENXIO;
+
+       res = request_mem_region(memory.start, memory.end - memory.start + 1,
+                       dev->dev.bus_id);
+       if (!res)
+               return -EBUSY;
+
+       res_len = memory.end - memory.start + 1;
+
+       if (of_irq_map_one(dp, 0, &oirq)) {
+               ret = -ENODEV;
+               goto release_reg;
+       }
+
+       virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+                       oirq.size);
+
+       hcd = isp1760_register(memory.start, res_len, virq,
+               IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+       if (IS_ERR(hcd)) {
+               ret = PTR_ERR(hcd);
+               goto release_reg;
+       }
+
+       dev_set_drvdata(&dev->dev, hcd);
+       return ret;
+
+release_reg:
+       release_mem_region(memory.start, memory.end - memory.start + 1);
+       return ret;
+}
+
+static int of_isp1760_remove(struct of_device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
+
+       dev_set_drvdata(&dev->dev, NULL);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+       return 0;
+}
+
+static struct of_device_id of_isp1760_match[] = {
+       {
+               .compatible = "nxp,usb-isp1760",
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, of_isp1760_match);
+
+static struct of_platform_driver isp1760_of_driver = {
+       .name           = "nxp-isp1760",
+       .match_table    = of_isp1760_match,
+       .probe          = of_isp1760_probe,
+       .remove         = of_isp1760_remove,
+};
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+static u32 nxp_pci_io_base;
+static u32 iolength;
+static u32 pci_mem_phy0;
+static u32 length;
+static u8 *chip_addr;
+static u8 *iobase;
+
+static int __devinit isp1761_pci_probe(struct pci_dev *dev,
+               const struct pci_device_id *id)
+{
+       u8 latency, limit;
+       __u32 reg_data;
+       int retry_count;
+       int length;
+       int status = 1;
+       struct usb_hcd *hcd;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       if (pci_enable_device(dev) < 0)
+               return -ENODEV;
+
+       if (!dev->irq)
+               return -ENODEV;
+
+       /* Grab the PLX PCI mem maped port start address we need  */
+       nxp_pci_io_base = pci_resource_start(dev, 0);
+       iolength = pci_resource_len(dev, 0);
+
+       if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
+               printk(KERN_ERR "request region #1\n");
+               return -EBUSY;
+       }
+
+       iobase = ioremap_nocache(nxp_pci_io_base, iolength);
+       if (!iobase) {
+               printk(KERN_ERR "ioremap #1\n");
+               release_mem_region(nxp_pci_io_base, iolength);
+               return -ENOMEM;
+       }
+       /* Grab the PLX PCI shared memory of the ISP 1761 we need  */
+       pci_mem_phy0 = pci_resource_start(dev, 3);
+       length = pci_resource_len(dev, 3);
+
+       if (length < 0xffff) {
+               printk(KERN_ERR "memory length for this resource is less than "
+                               "required\n");
+               release_mem_region(nxp_pci_io_base, iolength);
+               iounmap(iobase);
+               return  -ENOMEM;
+       }
+
+       if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
+               printk(KERN_ERR "host controller already in use\n");
+               release_mem_region(nxp_pci_io_base, iolength);
+               iounmap(iobase);
+               return -EBUSY;
+       }
+
+       /* bad pci latencies can contribute to overruns */
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+       if (latency) {
+               pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+               if (limit && limit < latency)
+                       pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
+       }
+
+       /* Try to check whether we can access Scratch Register of
+        * Host Controller or not. The initial PCI access is retried until
+        * local init for the PCI bridge is completed
+        */
+       retry_count = 20;
+       reg_data = 0;
+       while ((reg_data != 0xFACE) && retry_count) {
+               /*by default host is in 16bit mode, so
+                * io operations at this stage must be 16 bit
+                * */
+               writel(0xface, chip_addr + HC_SCRATCH_REG);
+               udelay(100);
+               reg_data = readl(chip_addr + HC_SCRATCH_REG);
+               retry_count--;
+       }
+
+       /* Host Controller presence is detected by writing to scratch register
+        * and reading back and checking the contents are same or not
+        */
+       if (reg_data != 0xFACE) {
+               err("scratch register mismatch %x", reg_data);
+               goto clean;
+       }
+
+       pci_set_master(dev);
+
+       status = readl(iobase + 0x68);
+       status |= 0x900;
+       writel(status, iobase + 0x68);
+
+       dev->dev.dma_mask = NULL;
+       hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
+               IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+       pci_set_drvdata(dev, hcd);
+       if (!hcd)
+               return 0;
+clean:
+       status = -ENODEV;
+       iounmap(iobase);
+       release_mem_region(pci_mem_phy0, length);
+       release_mem_region(nxp_pci_io_base, iolength);
+       return status;
+}
+static void isp1761_pci_remove(struct pci_dev *dev)
+{
+       struct usb_hcd *hcd;
+
+       hcd = pci_get_drvdata(dev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+
+       pci_disable_device(dev);
+
+       iounmap(iobase);
+       iounmap(chip_addr);
+
+       release_mem_region(nxp_pci_io_base, iolength);
+       release_mem_region(pci_mem_phy0, length);
+}
+
+static void isp1761_pci_shutdown(struct pci_dev *dev)
+{
+       printk(KERN_ERR "ips1761_pci_shutdown\n");
+}
+
+static const struct pci_device_id isp1760_plx [] = { {
+       /* handle any USB 2.0 EHCI controller */
+       PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
+               .driver_data = 0,
+},
+{ /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, isp1760_plx);
+
+static struct pci_driver isp1761_pci_driver = {
+       .name =         "isp1760",
+       .id_table =     isp1760_plx,
+       .probe =        isp1761_pci_probe,
+       .remove =       isp1761_pci_remove,
+       .shutdown =     isp1761_pci_shutdown,
+};
+#endif
+
+static int __init isp1760_init(void)
+{
+       int ret;
+
+       init_kmem_once();
+
+#ifdef CONFIG_USB_ISP1760_OF
+       ret = of_register_platform_driver(&isp1760_of_driver);
+       if (ret) {
+               deinit_kmem_cache();
+               return ret;
+       }
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+       ret = pci_register_driver(&isp1761_pci_driver);
+       if (ret)
+               goto unreg_of;
+#endif
+       return ret;
+
+#ifdef CONFIG_USB_ISP1760_PCI
+unreg_of:
+#endif
+#ifdef CONFIG_USB_ISP1760_OF
+       of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+       deinit_kmem_cache();
+       return ret;
+}
+module_init(isp1760_init);
+
+static void __exit isp1760_exit(void)
+{
+#ifdef CONFIG_USB_ISP1760_OF
+       of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+       pci_unregister_driver(&isp1761_pci_driver);
+#endif
+       deinit_kmem_cache();
+}
+module_exit(isp1760_exit);
index 17dc2eccda83e7d6dca6bfd725fbd87fdce8b649..79a78029f896869892fa2696bd8f1764cc79f9e7 100644 (file)
@@ -613,7 +613,7 @@ static void start_hnp(struct ohci_hcd *ohci);
 static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
 {
        __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
-       u32     temp;
+       u32     temp = 0;
        u16     now = ohci_readl(ohci, &ohci->regs->fmnumber);
        u16     reset_done = now + PORT_RESET_MSEC;
        int     limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC);
index d3e0d8aa398078f7c5c15313f19f656202dcafaa..3a7bfe7a8874c321990bb802910ea4a902671c9a 100644 (file)
@@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
        return 0;
 }
 
-static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
+static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
 {
        int port;
        const char *sys_info;
@@ -261,27 +261,60 @@ __releases(uhci->lock)
 __acquires(uhci->lock)
 {
        int auto_stop;
-       int int_enable, egsm_enable;
+       int int_enable, egsm_enable, wakeup_enable;
        struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
 
        auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
        dev_dbg(&rhdev->dev, "%s%s\n", __func__,
                        (auto_stop ? " (auto-stop)" : ""));
 
-       /* Enable resume-detect interrupts if they work.
-        * Then enter Global Suspend mode if _it_ works, still configured.
+       /* Start off by assuming Resume-Detect interrupts and EGSM work
+        * and that remote wakeups should be enabled.
         */
        egsm_enable = USBCMD_EGSM;
-       uhci->working_RD = 1;
+       uhci->RD_enable = 1;
        int_enable = USBINTR_RESUME;
-       if (remote_wakeup_is_broken(uhci))
-               egsm_enable = 0;
-       if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
+       wakeup_enable = 1;
+
+       /* In auto-stop mode wakeups must always be detected, but
+        * Resume-Detect interrupts may be prohibited.  (In the absence
+        * of CONFIG_PM, they are always disallowed.)
+        */
+       if (auto_stop) {
+               if (!device_may_wakeup(&rhdev->dev))
+                       int_enable = 0;
+
+       /* In bus-suspend mode wakeups may be disabled, but if they are
+        * allowed then so are Resume-Detect interrupts.
+        */
+       } else {
 #ifdef CONFIG_PM
-                       (!auto_stop && !rhdev->do_remote_wakeup) ||
+               if (!rhdev->do_remote_wakeup)
+                       wakeup_enable = 0;
 #endif
-                       (auto_stop && !device_may_wakeup(&rhdev->dev)))
-               uhci->working_RD = int_enable = 0;
+       }
+
+       /* EGSM causes the root hub to echo a 'K' signal (resume) out any
+        * port which requests a remote wakeup.  According to the USB spec,
+        * every hub is supposed to do this.  But if we are ignoring
+        * remote-wakeup requests anyway then there's no point to it.
+        * We also shouldn't enable EGSM if it's broken.
+        */
+       if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
+               egsm_enable = 0;
+
+       /* If we're ignoring wakeup events then there's no reason to
+        * enable Resume-Detect interrupts.  We also shouldn't enable
+        * them if they are broken or disallowed.
+        *
+        * This logic may lead us to enabling RD but not EGSM.  The UHCI
+        * spec foolishly says that RD works only when EGSM is on, but
+        * there's no harm in enabling it anyway -- perhaps some chips
+        * will implement it!
+        */
+       if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
+                       !int_enable)
+               uhci->RD_enable = int_enable = 0;
 
        outw(int_enable, uhci->io_addr + USBINTR);
        outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
@@ -308,7 +341,11 @@ __acquires(uhci->lock)
 
        uhci->rh_state = new_state;
        uhci->is_stopped = UHCI_IS_STOPPED;
-       uhci_to_hcd(uhci)->poll_rh = !int_enable;
+
+       /* If interrupts don't work and remote wakeup is enabled then
+        * the suspended root hub needs to be polled.
+        */
+       uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);
 
        uhci_scan_schedule(uhci);
        uhci_fsbr_off(uhci);
@@ -344,9 +381,12 @@ __acquires(uhci->lock)
         * for 20 ms.
         */
        if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+               unsigned egsm;
+
+               /* Keep EGSM on if it was set before */
+               egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
                uhci->rh_state = UHCI_RH_RESUMING;
-               outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
-                               uhci->io_addr + USBCMD);
+               outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
                spin_unlock_irq(&uhci->lock);
                msleep(20);
                spin_lock_irq(&uhci->lock);
@@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
 
        spin_unlock_irq(&uhci->lock);
 
-       if (!uhci->working_RD) {
-               /* Suspended root hub needs to be polled */
+       /* If interrupts don't work and remote wakeup is enabled then
+        * the suspended root hub needs to be polled.
+        */
+       if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
                hcd->poll_rh = 1;
                usb_hcd_poll_rh_status(hcd);
        }
index 340d6ed3e6e92006c858e80ee8bdcd5f0ef0b179..7d01c5677f92ced1517c73dc562e853c2e6990fa 100644 (file)
@@ -400,8 +400,9 @@ struct uhci_hcd {
        unsigned int scan_in_progress:1;        /* Schedule scan is running */
        unsigned int need_rescan:1;             /* Redo the schedule scan */
        unsigned int dead:1;                    /* Controller has died */
-       unsigned int working_RD:1;              /* Suspended root hub doesn't
-                                                  need to be polled */
+       unsigned int RD_enable:1;               /* Suspended root hub with
+                                                  Resume-Detect interrupts
+                                                  enabled */
        unsigned int is_initialized:1;          /* Data structure is usable */
        unsigned int fsbr_is_on:1;              /* FSBR is turned on */
        unsigned int fsbr_is_wanted:1;          /* Does any URB want FSBR? */
index 11580e81e2c633b0163214680342334105b64dc8..7aafd53fbcab8452c08b1c510e2f6537a7f8f987 100644 (file)
@@ -148,7 +148,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
 
 /* Structure to hold all of our device specific stuff */
 struct ld_usb {
-       struct semaphore        sem;            /* locks this structure */
+       struct mutex            mutex;          /* locks this structure */
        struct usb_interface*   intf;           /* save off the usb interface pointer */
 
        int                     open_count;     /* number of times this port has been opened */
@@ -319,7 +319,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
                return -ENODEV;
 
        /* lock this device */
-       if (down_interruptible(&dev->sem))
+       if (mutex_lock_interruptible(&dev->mutex))
                return -ERESTARTSYS;
 
        /* allow opening only once */
@@ -358,7 +358,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
        file->private_data = dev;
 
 unlock_exit:
-       up(&dev->sem);
+       mutex_unlock(&dev->mutex);
 
        return retval;
 }
@@ -378,7 +378,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
                goto exit;
        }
 
-       if (down_interruptible(&dev->sem)) {
+       if (mutex_lock_interruptible(&dev->mutex)) {
                retval = -ERESTARTSYS;
                goto exit;
        }
@@ -389,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
        }
        if (dev->intf == NULL) {
                /* the device was unplugged before the file was released */
-               up(&dev->sem);
+               mutex_unlock(&dev->mutex);
                /* unlock here as ld_usb_delete frees dev */
                ld_usb_delete(dev);
                goto exit;
@@ -402,7 +402,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
        dev->open_count = 0;
 
 unlock_exit:
-       up(&dev->sem);
+       mutex_unlock(&dev->mutex);
 
 exit:
        return retval;
@@ -448,7 +448,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
                goto exit;
 
        /* lock this object */
-       if (down_interruptible(&dev->sem)) {
+       if (mutex_lock_interruptible(&dev->mutex)) {
                retval = -ERESTARTSYS;
                goto exit;
        }
@@ -505,7 +505,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
 
 unlock_exit:
        /* unlock the device */
-       up(&dev->sem);
+       mutex_unlock(&dev->mutex);
 
 exit:
        return retval;
@@ -528,7 +528,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
                goto exit;
 
        /* lock this object */
-       if (down_interruptible(&dev->sem)) {
+       if (mutex_lock_interruptible(&dev->mutex)) {
                retval = -ERESTARTSYS;
                goto exit;
        }
@@ -602,7 +602,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
 
 unlock_exit:
        /* unlock the device */
-       up(&dev->sem);
+       mutex_unlock(&dev->mutex);
 
 exit:
        return retval;
@@ -651,7 +651,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
                dev_err(&intf->dev, "Out of memory\n");
                goto exit;
        }
-       init_MUTEX(&dev->sem);
+       mutex_init(&dev->mutex);
        spin_lock_init(&dev->rbsl);
        dev->intf = intf;
        init_waitqueue_head(&dev->read_wait);
@@ -765,15 +765,15 @@ static void ld_usb_disconnect(struct usb_interface *intf)
        /* give back our minor */
        usb_deregister_dev(intf, &ld_usb_class);
 
-       down(&dev->sem);
+       mutex_lock(&dev->mutex);
 
        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
-               up(&dev->sem);
+               mutex_unlock(&dev->mutex);
                ld_usb_delete(dev);
        } else {
                dev->intf = NULL;
-               up(&dev->sem);
+               mutex_unlock(&dev->mutex);
        }
 
        dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
index a51983854ca0625da79cbf97daa98b75090b4199..742be3c3594788b23464050e1a09afafed91fbde 100644 (file)
@@ -79,30 +79,10 @@ static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test)
 /* set up all urbs so they can be used with either bulk or interrupt */
 #define        INTERRUPT_RATE          1       /* msec/transfer */
 
-#define xprintk(tdev,level,fmt,args...) \
-       dev_printk(level ,  &(tdev)->intf->dev ,  fmt ,  ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-       xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-       xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-       xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-       xprintk(dev , KERN_INFO , fmt , ## args)
+#define ERROR(tdev, fmt, args...) \
+       dev_err(&(tdev)->intf->dev , fmt , ## args)
+#define WARN(tdev, fmt, args...) \
+       dev_warn(&(tdev)->intf->dev , fmt , ## args)
 
 /*-------------------------------------------------------------------------*/
 
@@ -236,7 +216,7 @@ static struct urb *simple_alloc_urb (
 
 static unsigned pattern = 0;
 module_param (pattern, uint, S_IRUGO);
-// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)");
+MODULE_PARM_DESC(pattern, "i/o pattern (0 == zeroes)");
 
 static inline void simple_fill_buf (struct urb *urb)
 {
@@ -257,7 +237,7 @@ static inline void simple_fill_buf (struct urb *urb)
        }
 }
 
-static inline int simple_check_buf (struct urb *urb)
+static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
 {
        unsigned        i;
        u8              expected;
@@ -285,7 +265,7 @@ static inline int simple_check_buf (struct urb *urb)
                }
                if (*buf == expected)
                        continue;
-               dbg ("buf[%d] = %d (not %d)", i, *buf, expected);
+               ERROR(tdev, "buf[%d] = %d (not %d)\n", i, *buf, expected);
                return -EINVAL;
        }
        return 0;
@@ -299,6 +279,7 @@ static void simple_free_urb (struct urb *urb)
 }
 
 static int simple_io (
+       struct usbtest_dev      *tdev,
        struct urb              *urb,
        int                     iterations,
        int                     vary,
@@ -324,7 +305,7 @@ static int simple_io (
                retval = urb->status;
                urb->dev = udev;
                if (retval == 0 && usb_pipein (urb->pipe))
-                       retval = simple_check_buf (urb);
+                       retval = simple_check_buf(tdev, urb);
 
                if (vary) {
                        int     len = urb->transfer_buffer_length;
@@ -341,7 +322,7 @@ static int simple_io (
        urb->transfer_buffer_length = max;
 
        if (expected != retval)
-               dev_dbg (&udev->dev,
+               dev_err(&udev->dev,
                        "%s failed, iterations left %d, status %d (not %d)\n",
                                label, iterations, retval, expected);
        return retval;
@@ -357,7 +338,7 @@ static int simple_io (
 static void free_sglist (struct scatterlist *sg, int nents)
 {
        unsigned                i;
-       
+
        if (!sg)
                return;
        for (i = 0; i < nents; i++) {
@@ -415,7 +396,7 @@ alloc_sglist (int nents, int max, int vary)
 }
 
 static int perform_sglist (
-       struct usb_device       *udev,
+       struct usbtest_dev      *tdev,
        unsigned                iterations,
        int                     pipe,
        struct usb_sg_request   *req,
@@ -423,6 +404,7 @@ static int perform_sglist (
        int                     nents
 )
 {
+       struct usb_device       *udev = testdev_to_usbdev(tdev);
        int                     retval = 0;
 
        while (retval == 0 && iterations-- > 0) {
@@ -431,7 +413,7 @@ static int perform_sglist (
                                        ? (INTERRUPT_RATE << 3)
                                        : INTERRUPT_RATE,
                                sg, nents, 0, GFP_KERNEL);
-               
+
                if (retval)
                        break;
                usb_sg_wait (req);
@@ -446,7 +428,8 @@ static int perform_sglist (
        // failure if retval is as we expected ...
 
        if (retval)
-               dbg ("perform_sglist failed, iterations left %d, status %d",
+               ERROR(tdev, "perform_sglist failed, "
+                               "iterations left %d, status %d\n",
                                iterations, retval);
        return retval;
 }
@@ -505,28 +488,28 @@ static int set_altsetting (struct usbtest_dev *dev, int alternate)
                        alternate);
 }
 
-static int is_good_config (char *buf, int len)
+static int is_good_config(struct usbtest_dev *tdev, int len)
 {
        struct usb_config_descriptor    *config;
-       
+
        if (len < sizeof *config)
                return 0;
-       config = (struct usb_config_descriptor *) buf;
+       config = (struct usb_config_descriptor *) tdev->buf;
 
        switch (config->bDescriptorType) {
        case USB_DT_CONFIG:
        case USB_DT_OTHER_SPEED_CONFIG:
                if (config->bLength != 9) {
-                       dbg ("bogus config descriptor length");
+                       ERROR(tdev, "bogus config descriptor length\n");
                        return 0;
                }
                /* this bit 'must be 1' but often isn't */
                if (!realworld && !(config->bmAttributes & 0x80)) {
-                       dbg ("high bit of config attributes not set");
+                       ERROR(tdev, "high bit of config attributes not set\n");
                        return 0;
                }
                if (config->bmAttributes & 0x1f) {      /* reserved == 0 */
-                       dbg ("reserved config bits set");
+                       ERROR(tdev, "reserved config bits set\n");
                        return 0;
                }
                break;
@@ -538,7 +521,7 @@ static int is_good_config (char *buf, int len)
                return 1;
        if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE)             /* max partial read */
                return 1;
-       dbg ("bogus config descriptor read size");
+       ERROR(tdev, "bogus config descriptor read size\n");
        return 0;
 }
 
@@ -571,7 +554,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
                /* 9.2.3 constrains the range here */
                alt = iface->altsetting [i].desc.bAlternateSetting;
                if (alt < 0 || alt >= iface->num_altsetting) {
-                       dev_dbg (&iface->dev,
+                       dev_err(&iface->dev,
                                        "invalid alt [%d].bAltSetting = %d\n",
                                        i, alt);
                }
@@ -583,7 +566,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
                /* [9.4.10] set_interface */
                retval = set_altsetting (dev, alt);
                if (retval) {
-                       dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
+                       dev_err(&iface->dev, "can't set_interface = %d, %d\n",
                                        alt, retval);
                        return retval;
                }
@@ -591,7 +574,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
                /* [9.4.4] get_interface always works */
                retval = get_altsetting (dev);
                if (retval != alt) {
-                       dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
+                       dev_err(&iface->dev, "get alt should be %d, was %d\n",
                                        alt, retval);
                        return (retval < 0) ? retval : -EDOM;
                }
@@ -611,7 +594,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
                                USB_DIR_IN | USB_RECIP_DEVICE,
                                0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
                if (retval != 1 || dev->buf [0] != expected) {
-                       dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+                       dev_err(&iface->dev, "get config --> %d %d (1 %d)\n",
                                retval, dev->buf[0], expected);
                        return (retval < 0) ? retval : -EDOM;
                }
@@ -621,7 +604,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
        retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0,
                        dev->buf, sizeof udev->descriptor);
        if (retval != sizeof udev->descriptor) {
-               dev_dbg (&iface->dev, "dev descriptor --> %d\n", retval);
+               dev_err(&iface->dev, "dev descriptor --> %d\n", retval);
                return (retval < 0) ? retval : -EDOM;
        }
 
@@ -629,8 +612,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
        for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
                retval = usb_get_descriptor (udev, USB_DT_CONFIG, i,
                                dev->buf, TBUF_SIZE);
-               if (!is_good_config (dev->buf, retval)) {
-                       dev_dbg (&iface->dev,
+               if (!is_good_config(dev, retval)) {
+                       dev_err(&iface->dev,
                                        "config [%d] descriptor --> %d\n",
                                        i, retval);
                        return (retval < 0) ? retval : -EDOM;
@@ -650,14 +633,14 @@ static int ch9_postconfig (struct usbtest_dev *dev)
                                sizeof (struct usb_qualifier_descriptor));
                if (retval == -EPIPE) {
                        if (udev->speed == USB_SPEED_HIGH) {
-                               dev_dbg (&iface->dev,
+                               dev_err(&iface->dev,
                                                "hs dev qualifier --> %d\n",
                                                retval);
                                return (retval < 0) ? retval : -EDOM;
                        }
                        /* usb2.0 but not high-speed capable; fine */
                } else if (retval != sizeof (struct usb_qualifier_descriptor)) {
-                       dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval);
+                       dev_err(&iface->dev, "dev qualifier --> %d\n", retval);
                        return (retval < 0) ? retval : -EDOM;
                } else
                        d = (struct usb_qualifier_descriptor *) dev->buf;
@@ -669,8 +652,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
                                retval = usb_get_descriptor (udev,
                                        USB_DT_OTHER_SPEED_CONFIG, i,
                                        dev->buf, TBUF_SIZE);
-                               if (!is_good_config (dev->buf, retval)) {
-                                       dev_dbg (&iface->dev,
+                               if (!is_good_config(dev, retval)) {
+                                       dev_err(&iface->dev,
                                                "other speed config --> %d\n",
                                                retval);
                                        return (retval < 0) ? retval : -EDOM;
@@ -683,7 +666,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
        /* [9.4.5] get_status always works */
        retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);
        if (retval != 2) {
-               dev_dbg (&iface->dev, "get dev status --> %d\n", retval);
+               dev_err(&iface->dev, "get dev status --> %d\n", retval);
                return (retval < 0) ? retval : -EDOM;
        }
 
@@ -693,11 +676,11 @@ static int ch9_postconfig (struct usbtest_dev *dev)
        retval = usb_get_status (udev, USB_RECIP_INTERFACE,
                        iface->altsetting [0].desc.bInterfaceNumber, dev->buf);
        if (retval != 2) {
-               dev_dbg (&iface->dev, "get interface status --> %d\n", retval);
+               dev_err(&iface->dev, "get interface status --> %d\n", retval);
                return (retval < 0) ? retval : -EDOM;
        }
        // FIXME get status for each endpoint in the interface
-       
+
        return 0;
 }
 
@@ -752,8 +735,9 @@ static void ctrl_complete (struct urb *urb)
         */
        if (subcase->number > 0) {
                if ((subcase->number - ctx->last) != 1) {
-                       dbg ("subcase %d completed out of order, last %d",
-                                       subcase->number, ctx->last);
+                       ERROR(ctx->dev,
+                               "subcase %d completed out of order, last %d\n",
+                               subcase->number, ctx->last);
                        status = -EDOM;
                        ctx->last = subcase->number;
                        goto error;
@@ -777,7 +761,7 @@ static void ctrl_complete (struct urb *urb)
                else if (subcase->number == 12 && status == -EPIPE)
                        status = 0;
                else
-                       dbg ("subtest %d error, status %d",
+                       ERROR(ctx->dev, "subtest %d error, status %d\n",
                                        subcase->number, status);
        }
 
@@ -788,9 +772,12 @@ error:
                        int             i;
 
                        ctx->status = status;
-                       info ("control queue %02x.%02x, err %d, %d left",
+                       ERROR(ctx->dev, "control queue %02x.%02x, err %d, "
+                                       "%d left, subcase %d, len %d/%d\n",
                                        reqp->bRequestType, reqp->bRequest,
-                                       status, ctx->count);
+                                       status, ctx->count, subcase->number,
+                                       urb->actual_length,
+                                       urb->transfer_buffer_length);
 
                        /* FIXME this "unlink everything" exit route should
                         * be a separate test case.
@@ -799,7 +786,8 @@ error:
                        /* unlink whatever's still pending */
                        for (i = 1; i < ctx->param->sglen; i++) {
                                struct urb      *u = ctx->urb [
-       (i + subcase->number) % ctx->param->sglen];
+                                               (i + subcase->number)
+                                               % ctx->param->sglen];
 
                                if (u == urb || !u->dev)
                                        continue;
@@ -812,7 +800,8 @@ error:
                                case -EIDRM:
                                        continue;
                                default:
-                                       dbg ("urb unlink --> %d", status);
+                                       ERROR(ctx->dev, "urb unlink --> %d\n",
+                                                       status);
                                }
                        }
                        status = ctx->status;
@@ -822,14 +811,15 @@ error:
        /* resubmit if we need to, else mark this as done */
        if ((status == 0) && (ctx->pending < ctx->count)) {
                if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
-                       dbg ("can't resubmit ctrl %02x.%02x, err %d",
+                       ERROR(ctx->dev,
+                               "can't resubmit ctrl %02x.%02x, err %d\n",
                                reqp->bRequestType, reqp->bRequest, status);
                        urb->dev = NULL;
                } else
                        ctx->pending++;
        } else
                urb->dev = NULL;
-       
+
        /* signal completion when nothing's queued */
        if (ctx->pending == 0)
                complete (&ctx->complete);
@@ -918,11 +908,11 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
                        req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
                        // interface == 0
                        len = sizeof (struct usb_interface_descriptor);
-                       expected = EPIPE;
+                       expected = -EPIPE;
                        break;
                // NOTE: two consecutive stalls in the queue here.
                // that tests fault recovery a bit more aggressively.
-               case 8:         // clear endpoint halt (USUALLY STALLS)
+               case 8:         // clear endpoint halt (MAY STALL)
                        req.bRequest = USB_REQ_CLEAR_FEATURE;
                        req.bRequestType = USB_RECIP_ENDPOINT;
                        // wValue 0 == ep halt
@@ -965,7 +955,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
                        break;
                case 14:        // short read; try to fill the last packet
                        req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0);
-                       // device descriptor size == 18 bytes 
+                       /* device descriptor size == 18 bytes */
                        len = udev->descriptor.bMaxPacketSize0;
                        switch (len) {
                        case 8:         len = 24; break;
@@ -974,7 +964,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
                        expected = -EREMOTEIO;
                        break;
                default:
-                       err ("bogus number of ctrl queue testcases!");
+                       ERROR(dev, "bogus number of ctrl queue testcases!\n");
                        context.status = -EINVAL;
                        goto cleanup;
                }
@@ -1003,7 +993,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
        for (i = 0; i < param->sglen; i++) {
                context.status = usb_submit_urb (urb [i], GFP_ATOMIC);
                if (context.status != 0) {
-                       dbg ("can't submit urb[%d], status %d",
+                       ERROR(dev, "can't submit urb[%d], status %d\n",
                                        i, context.status);
                        context.count = context.pending;
                        break;
@@ -1070,7 +1060,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
         * due to errors, or is just NAKing requests.
         */
        if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) {
-               dev_dbg (&dev->intf->dev, "submit fail %d\n", retval);
+               dev_err(&dev->intf->dev, "submit fail %d\n", retval);
                return retval;
        }
 
@@ -1087,13 +1077,13 @@ retry:
                         * "normal" drivers would prevent resubmission, but
                         * since we're testing unlink paths, we can't.
                         */
-                       dev_dbg (&dev->intf->dev, "unlink retry\n");
+                       ERROR(dev,  "unlink retry\n");
                        goto retry;
                }
        } else
                usb_kill_urb (urb);
        if (!(retval == 0 || retval == -EINPROGRESS)) {
-               dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval);
+               dev_err(&dev->intf->dev, "unlink fail %d\n", retval);
                return retval;
        }
 
@@ -1121,7 +1111,7 @@ static int unlink_simple (struct usbtest_dev *dev, int pipe, int len)
 
 /*-------------------------------------------------------------------------*/
 
-static int verify_not_halted (int ep, struct urb *urb)
+static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
 {
        int     retval;
        u16     status;
@@ -1129,20 +1119,21 @@ static int verify_not_halted (int ep, struct urb *urb)
        /* shouldn't look or act halted */
        retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
        if (retval < 0) {
-               dbg ("ep %02x couldn't get no-halt status, %d", ep, retval);
+               ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n",
+                               ep, retval);
                return retval;
        }
        if (status != 0) {
-               dbg ("ep %02x bogus status: %04x != 0", ep, status);
+               ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status);
                return -EINVAL;
        }
-       retval = simple_io (urb, 1, 0, 0, __func__);
+       retval = simple_io(tdev, urb, 1, 0, 0, __func__);
        if (retval != 0)
                return -EINVAL;
        return 0;
 }
 
-static int verify_halted (int ep, struct urb *urb)
+static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
 {
        int     retval;
        u16     status;
@@ -1150,29 +1141,30 @@ static int verify_halted (int ep, struct urb *urb)
        /* should look and act halted */
        retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
        if (retval < 0) {
-               dbg ("ep %02x couldn't get halt status, %d", ep, retval);
+               ERROR(tdev, "ep %02x couldn't get halt status, %d\n",
+                               ep, retval);
                return retval;
        }
        le16_to_cpus(&status);
        if (status != 1) {
-               dbg ("ep %02x bogus status: %04x != 1", ep, status);
+               ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
                return -EINVAL;
        }
-       retval = simple_io (urb, 1, 0, -EPIPE, __func__);
+       retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__);
        if (retval != -EPIPE)
                return -EINVAL;
-       retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");
+       retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted");
        if (retval != -EPIPE)
                return -EINVAL;
        return 0;
 }
 
-static int test_halt (int ep, struct urb *urb)
+static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
 {
        int     retval;
 
        /* shouldn't look or act halted now */
-       retval = verify_not_halted (ep, urb);
+       retval = verify_not_halted(tdev, ep, urb);
        if (retval < 0)
                return retval;
 
@@ -1182,20 +1174,20 @@ static int test_halt (int ep, struct urb *urb)
                        USB_ENDPOINT_HALT, ep,
                        NULL, 0, USB_CTRL_SET_TIMEOUT);
        if (retval < 0) {
-               dbg ("ep %02x couldn't set halt, %d", ep, retval);
+               ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval);
                return retval;
        }
-       retval = verify_halted (ep, urb);
+       retval = verify_halted(tdev, ep, urb);
        if (retval < 0)
                return retval;
 
        /* clear halt (tests API + protocol), verify it worked */
        retval = usb_clear_halt (urb->dev, urb->pipe);
        if (retval < 0) {
-               dbg ("ep %02x couldn't clear halt, %d", ep, retval);
+               ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
                return retval;
        }
-       retval = verify_not_halted (ep, urb);
+       retval = verify_not_halted(tdev, ep, urb);
        if (retval < 0)
                return retval;
 
@@ -1217,7 +1209,7 @@ static int halt_simple (struct usbtest_dev *dev)
        if (dev->in_pipe) {
                ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN;
                urb->pipe = dev->in_pipe;
-               retval = test_halt (ep, urb);
+               retval = test_halt(dev, ep, urb);
                if (retval < 0)
                        goto done;
        }
@@ -1225,7 +1217,7 @@ static int halt_simple (struct usbtest_dev *dev)
        if (dev->out_pipe) {
                ep = usb_pipeendpoint (dev->out_pipe);
                urb->pipe = dev->out_pipe;
-               retval = test_halt (ep, urb);
+               retval = test_halt(dev, ep, urb);
        }
 done:
        simple_free_urb (urb);
@@ -1275,7 +1267,7 @@ static int ctrl_out (struct usbtest_dev *dev,
                if (retval != len) {
                        what = "write";
                        if (retval >= 0) {
-                               INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+                               ERROR(dev, "ctrl_out, wlen %d (expected %d)\n",
                                                retval, len);
                                retval = -EBADMSG;
                        }
@@ -1289,7 +1281,7 @@ static int ctrl_out (struct usbtest_dev *dev,
                if (retval != len) {
                        what = "read";
                        if (retval >= 0) {
-                               INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+                               ERROR(dev, "ctrl_out, rlen %d (expected %d)\n",
                                                retval, len);
                                retval = -EBADMSG;
                        }
@@ -1299,7 +1291,7 @@ static int ctrl_out (struct usbtest_dev *dev,
                /* fail if we can't verify */
                for (j = 0; j < len; j++) {
                        if (buf [j] != (u8) (i + j)) {
-                               INFO (dev, "ctrl_out, byte %d is %d not %d\n",
+                               ERROR(dev, "ctrl_out, byte %d is %d not %d\n",
                                        j, buf [j], (u8) i + j);
                                retval = -EBADMSG;
                                break;
@@ -1321,7 +1313,7 @@ static int ctrl_out (struct usbtest_dev *dev,
        }
 
        if (retval < 0)
-               INFO (dev, "ctrl_out %s failed, code %d, count %d\n",
+               ERROR (dev, "ctrl_out %s failed, code %d, count %d\n",
                        what, retval, i);
 
        kfree (buf);
@@ -1366,7 +1358,7 @@ static void iso_callback (struct urb *urb)
                case 0:
                        goto done;
                default:
-                       dev_dbg (&ctx->dev->intf->dev,
+                       dev_err(&ctx->dev->intf->dev,
                                        "iso resubmit err %d\n",
                                        status);
                        /* FALLTHROUGH */
@@ -1381,7 +1373,7 @@ static void iso_callback (struct urb *urb)
        ctx->pending--;
        if (ctx->pending == 0) {
                if (ctx->errors)
-                       dev_dbg (&ctx->dev->intf->dev,
+                       dev_err(&ctx->dev->intf->dev,
                                "iso test, %lu errors out of %lu\n",
                                ctx->errors, ctx->packet_count);
                complete (&ctx->done);
@@ -1458,7 +1450,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
 
        memset (urbs, 0, sizeof urbs);
        udev = testdev_to_usbdev (dev);
-       dev_dbg (&dev->intf->dev,
+       dev_info(&dev->intf->dev,
                "... iso period %d %sframes, wMaxPacket %04x\n",
                1 << (desc->bInterval - 1),
                (udev->speed == USB_SPEED_HIGH) ? "micro" : "",
@@ -1475,7 +1467,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param,
                urbs [i]->context = &context;
        }
        packets *= param->iterations;
-       dev_dbg (&dev->intf->dev,
+       dev_info(&dev->intf->dev,
                "... total %lu msec (%lu packets)\n",
                (packets * (1 << (desc->bInterval - 1)))
                        / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
@@ -1537,6 +1529,13 @@ fail:
  * except indirectly by consuming USB bandwidth and CPU resources for test
  * threads and request completion.  But the only way to know that for sure
  * is to test when HC queues are in use by many devices.
+ *
+ * WARNING:  Because usbfs grabs udev->dev.sem before calling this ioctl(),
+ * it locks out usbcore in certain code paths.  Notably, if you disconnect
+ * the device-under-test, khubd will wait block forever waiting for the
+ * ioctl to complete ... so that usb_disconnect() can abort the pending
+ * urbs and then call usbtest_disconnect().  To abort a test, you're best
+ * off just killing the userspace task and waiting for it to exit.
  */
 
 static int
@@ -1575,7 +1574,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
         * altsettings; force a default so most tests don't need to check.
         */
        if (dev->info->alt >= 0) {
-               int     res;
+               int     res;
 
                if (intf->altsetting->desc.bInterfaceNumber) {
                        mutex_unlock(&dev->lock);
@@ -1604,7 +1603,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        switch (param->test_num) {
 
        case 0:
-               dev_dbg (&intf->dev, "TEST 0:  NOP\n");
+               dev_info(&intf->dev, "TEST 0:  NOP\n");
                retval = 0;
                break;
 
@@ -1612,7 +1611,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        case 1:
                if (dev->out_pipe == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                                "TEST 1:  write %d bytes %u times\n",
                                param->length, param->iterations);
                urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1621,13 +1620,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk sink (maybe accepts short writes)
-               retval = simple_io (urb, param->iterations, 0, 0, "test1");
+               retval = simple_io(dev, urb, param->iterations, 0, 0, "test1");
                simple_free_urb (urb);
                break;
        case 2:
                if (dev->in_pipe == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                                "TEST 2:  read %d bytes %u times\n",
                                param->length, param->iterations);
                urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1636,13 +1635,13 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk source (maybe generates short writes)
-               retval = simple_io (urb, param->iterations, 0, 0, "test2");
+               retval = simple_io(dev, urb, param->iterations, 0, 0, "test2");
                simple_free_urb (urb);
                break;
        case 3:
                if (dev->out_pipe == 0 || param->vary == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                                "TEST 3:  write/%d 0..%d bytes %u times\n",
                                param->vary, param->length, param->iterations);
                urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1651,14 +1650,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk sink (maybe accepts short writes)
-               retval = simple_io (urb, param->iterations, param->vary,
+               retval = simple_io(dev, urb, param->iterations, param->vary,
                                        0, "test3");
                simple_free_urb (urb);
                break;
        case 4:
                if (dev->in_pipe == 0 || param->vary == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                                "TEST 4:  read/%d 0..%d bytes %u times\n",
                                param->vary, param->length, param->iterations);
                urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1667,7 +1666,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk source (maybe generates short writes)
-               retval = simple_io (urb, param->iterations, param->vary,
+               retval = simple_io(dev, urb, param->iterations, param->vary,
                                        0, "test4");
                simple_free_urb (urb);
                break;
@@ -1676,7 +1675,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        case 5:
                if (dev->out_pipe == 0 || param->sglen == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                        "TEST 5:  write %d sglists %d entries of %d bytes\n",
                                param->iterations,
                                param->sglen, param->length);
@@ -1686,7 +1685,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk sink (maybe accepts short writes)
-               retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+               retval = perform_sglist(dev, param->iterations, dev->out_pipe,
                                &req, sg, param->sglen);
                free_sglist (sg, param->sglen);
                break;
@@ -1694,7 +1693,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        case 6:
                if (dev->in_pipe == 0 || param->sglen == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                        "TEST 6:  read %d sglists %d entries of %d bytes\n",
                                param->iterations,
                                param->sglen, param->length);
@@ -1704,14 +1703,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk source (maybe generates short writes)
-               retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+               retval = perform_sglist(dev, param->iterations, dev->in_pipe,
                                &req, sg, param->sglen);
                free_sglist (sg, param->sglen);
                break;
        case 7:
                if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                        "TEST 7:  write/%d %d sglists %d entries 0..%d bytes\n",
                                param->vary, param->iterations,
                                param->sglen, param->length);
@@ -1721,14 +1720,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk sink (maybe accepts short writes)
-               retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+               retval = perform_sglist(dev, param->iterations, dev->out_pipe,
                                &req, sg, param->sglen);
                free_sglist (sg, param->sglen);
                break;
        case 8:
                if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                        "TEST 8:  read/%d %d sglists %d entries 0..%d bytes\n",
                                param->vary, param->iterations,
                                param->sglen, param->length);
@@ -1738,7 +1737,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        break;
                }
                // FIRMWARE:  bulk source (maybe generates short writes)
-               retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+               retval = perform_sglist(dev, param->iterations, dev->in_pipe,
                                &req, sg, param->sglen);
                free_sglist (sg, param->sglen);
                break;
@@ -1746,13 +1745,14 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        /* non-queued sanity tests for control (chapter 9 subset) */
        case 9:
                retval = 0;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                        "TEST 9:  ch9 (subset) control tests, %d times\n",
                                param->iterations);
                for (i = param->iterations; retval == 0 && i--; /* NOP */)
                        retval = ch9_postconfig (dev);
                if (retval)
-                       dbg ("ch9 subset failed, iterations left %d", i);
+                       dev_err(&intf->dev, "ch9 subset failed, "
+                                       "iterations left %d\n", i);
                break;
 
        /* queued control messaging */
@@ -1760,7 +1760,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                if (param->sglen == 0)
                        break;
                retval = 0;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                                "TEST 10:  queue %d control calls, %d times\n",
                                param->sglen,
                                param->iterations);
@@ -1772,26 +1772,26 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                if (dev->in_pipe == 0 || !param->length)
                        break;
                retval = 0;
-               dev_dbg (&intf->dev, "TEST 11:  unlink %d reads of %d\n",
+               dev_info(&intf->dev, "TEST 11:  unlink %d reads of %d\n",
                                param->iterations, param->length);
                for (i = param->iterations; retval == 0 && i--; /* NOP */)
                        retval = unlink_simple (dev, dev->in_pipe,
                                                param->length);
                if (retval)
-                       dev_dbg (&intf->dev, "unlink reads failed %d, "
+                       dev_err(&intf->dev, "unlink reads failed %d, "
                                "iterations left %d\n", retval, i);
                break;
        case 12:
                if (dev->out_pipe == 0 || !param->length)
                        break;
                retval = 0;
-               dev_dbg (&intf->dev, "TEST 12:  unlink %d writes of %d\n",
+               dev_info(&intf->dev, "TEST 12:  unlink %d writes of %d\n",
                                param->iterations, param->length);
                for (i = param->iterations; retval == 0 && i--; /* NOP */)
                        retval = unlink_simple (dev, dev->out_pipe,
                                                param->length);
                if (retval)
-                       dev_dbg (&intf->dev, "unlink writes failed %d, "
+                       dev_err(&intf->dev, "unlink writes failed %d, "
                                "iterations left %d\n", retval, i);
                break;
 
@@ -1800,24 +1800,24 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                if (dev->out_pipe == 0 && dev->in_pipe == 0)
                        break;
                retval = 0;
-               dev_dbg (&intf->dev, "TEST 13:  set/clear %d halts\n",
+               dev_info(&intf->dev, "TEST 13:  set/clear %d halts\n",
                                param->iterations);
                for (i = param->iterations; retval == 0 && i--; /* NOP */)
                        retval = halt_simple (dev);
-               
+
                if (retval)
-                       DBG (dev, "halts failed, iterations left %d\n", i);
+                       ERROR(dev, "halts failed, iterations left %d\n", i);
                break;
 
        /* control write tests */
        case 14:
                if (!dev->info->ctrl_out)
                        break;
-               dev_dbg (&intf->dev, "TEST 14:  %d ep0out, %d..%d vary %d\n",
+               dev_info(&intf->dev, "TEST 14:  %d ep0out, %d..%d vary %d\n",
                                param->iterations,
                                realworld ? 1 : 0, param->length,
                                param->vary);
-               retval = ctrl_out (dev, param->iterations, 
+               retval = ctrl_out(dev, param->iterations,
                                param->length, param->vary);
                break;
 
@@ -1825,7 +1825,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        case 15:
                if (dev->out_iso_pipe == 0 || param->sglen == 0)
                        break;
-               dev_dbg (&intf->dev, 
+               dev_info(&intf->dev,
                        "TEST 15:  write %d iso, %d entries of %d bytes\n",
                                param->iterations,
                                param->sglen, param->length);
@@ -1838,7 +1838,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
        case 16:
                if (dev->in_iso_pipe == 0 || param->sglen == 0)
                        break;
-               dev_dbg (&intf->dev,
+               dev_info(&intf->dev,
                        "TEST 16:  read %d iso, %d entries of %d bytes\n",
                                param->iterations,
                                param->sglen, param->length);
@@ -1898,7 +1898,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
                        return -ENODEV;
                if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product)
                        return -ENODEV;
-               dbg ("matched module params, vend=0x%04x prod=0x%04x",
+               dev_info(&intf->dev, "matched module params, "
+                                       "vend=0x%04x prod=0x%04x\n",
                                le16_to_cpu(udev->descriptor.idVendor),
                                le16_to_cpu(udev->descriptor.idProduct));
        }
@@ -1940,7 +1941,8 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
 
                        status = get_endpoints (dev, intf);
                        if (status < 0) {
-                               dbg ("couldn't get endpoints, %d\n", status);
+                               WARN(dev, "couldn't get endpoints, %d\n",
+                                               status);
                                return status;
                        }
                        /* may find bulk or ISO pipes */
@@ -2082,21 +2084,9 @@ static struct usbtest_info generic_info = {
 };
 #endif
 
-// FIXME remove this 
-static struct usbtest_info hact_info = {
-       .name           = "FX2/hact",
-       //.ep_in                = 6,
-       .ep_out         = 2,
-       .alt            = -1,
-};
-
 
 static struct usb_device_id id_table [] = {
 
-       { USB_DEVICE (0x0547, 0x1002),
-               .driver_info = (unsigned long) &hact_info,
-               },
-
        /*-------------------------------------------------------------*/
 
        /* EZ-USB devices which download firmware to replace (or in our
@@ -2185,7 +2175,7 @@ static int __init usbtest_init (void)
 {
 #ifdef GENERIC
        if (vendor)
-               dbg ("params: vend=0x%04x prod=0x%04x", vendor, product);
+               pr_debug("params: vend=0x%04x prod=0x%04x\n", vendor, product);
 #endif
        return usb_register (&usbtest_driver);
 }
index 9b1bb347dc2d7e0b1865c4f36191118b207e5dde..db6f97a93c02c3b813e8feafd17ba6cb2acb1efc 100644 (file)
@@ -147,7 +147,7 @@ static void serial_buf_free(struct circ_buf *cb)
  */
 static int serial_buf_data_avail(struct circ_buf *cb)
 {
-       return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
+       return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
 }
 
 /*
@@ -171,7 +171,7 @@ static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
                cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
                buf += c;
                count -= c;
-               ret= c;
+               ret = c;
        }
        return ret;
 }
@@ -197,7 +197,7 @@ static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
                cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
                buf += c;
                count -= c;
-               ret= c;
+               ret = c;
        }
        return ret;
 }
@@ -208,7 +208,7 @@ static void aircable_send(struct usb_serial_port *port)
 {
        int count, result;
        struct aircable_private *priv = usb_get_serial_port_data(port);
-       unsigned charbuf;
+       unsigned char *buf;
        __le16 *dbuf;
        dbg("%s - port %d", __func__, port->number);
        if (port->write_urb_busy)
@@ -229,7 +229,8 @@ static void aircable_send(struct usb_serial_port *port)
        buf[1] = TX_HEADER_1;
        dbuf = (__le16 *)&buf[2];
        *dbuf = cpu_to_le16((u16)count);
-       serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
+       serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH,
+                                                       MAX_HCI_FRAMESIZE);
 
        memcpy(port->write_urb->transfer_buffer, buf,
               count + HCI_HEADER_LENGTH);
@@ -261,7 +262,7 @@ static void aircable_read(struct work_struct *work)
        struct tty_struct *tty;
        unsigned char *data;
        int count;
-       if (priv->rx_flags & THROTTLED){
+       if (priv->rx_flags & THROTTLED) {
                if (priv->rx_flags & ACTUALLY_THROTTLED)
                        schedule_work(&priv->rx_work);
                return;
@@ -282,10 +283,10 @@ static void aircable_read(struct work_struct *work)
        count = min(64, serial_buf_data_avail(priv->rx_buf));
 
        if (count <= 0)
-               return; //We have finished sending everything.
+               return; /* We have finished sending everything. */
 
        tty_prepare_flip_string(tty, &data, count);
-       if (!data){
+       if (!data) {
                err("%s- kzalloc(%d) failed.", __func__, count);
                return;
        }
@@ -304,9 +305,10 @@ static void aircable_read(struct work_struct *work)
 static int aircable_probe(struct usb_serial *serial,
                          const struct usb_device_id *id)
 {
-       struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
+       struct usb_host_interface *iface_desc = serial->interface->
+                                                               cur_altsetting;
        struct usb_endpoint_descriptor *endpoint;
-       int num_bulk_out=0;
+       int num_bulk_out = 0;
        int i;
 
        for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
@@ -325,13 +327,13 @@ static int aircable_probe(struct usb_serial *serial,
        return 0;
 }
 
-static int aircable_attach (struct usb_serial *serial)
+static int aircable_attach(struct usb_serial *serial)
 {
        struct usb_serial_port *port = serial->port[0];
        struct aircable_private *priv;
 
        priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
-       if (!priv){
+       if (!priv) {
                err("%s- kmalloc(%Zd) failed.", __func__,
                        sizeof(struct aircable_private));
                return -ENOMEM;
@@ -392,7 +394,7 @@ static int aircable_write(struct usb_serial_port *port,
 
        usb_serial_debug_data(debug, &port->dev, __func__, count, source);
 
-       if (!count){
+       if (!count) {
                dbg("%s - write request of 0 bytes", __func__);
                return count;
        }
@@ -418,31 +420,31 @@ static void aircable_write_bulk_callback(struct urb *urb)
 
        /* This has been taken from cypress_m8.c cypress_write_int_callback */
        switch (status) {
-               case 0:
-                       /* success */
-                       break;
-               case -ECONNRESET:
-               case -ENOENT:
-               case -ESHUTDOWN:
-                       /* this urb is terminated, clean up */
-                       dbg("%s - urb shutting down with status: %d",
-                           __func__, status);
-                       port->write_urb_busy = 0;
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d",
+                   __func__, status);
+               port->write_urb_busy = 0;
+               return;
+       default:
+               /* error in the urb, so we have to resubmit it */
+               dbg("%s - Overflow in write", __func__);
+               dbg("%s - nonzero write bulk status received: %d",
+                   __func__, status);
+               port->write_urb->transfer_buffer_length = 1;
+               port->write_urb->dev = port->serial->dev;
+               result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+               if (result)
+                       dev_err(&urb->dev->dev,
+                           "%s - failed resubmitting write urb, error %d\n",
+                                                       __func__, result);
+               else
                        return;
-               default:
-                       /* error in the urb, so we have to resubmit it */
-                       dbg("%s - Overflow in write", __func__);
-                       dbg("%s - nonzero write bulk status received: %d",
-                           __func__, status);
-                       port->write_urb->transfer_buffer_length = 1;
-                       port->write_urb->dev = port->serial->dev;
-                       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-                       if (result)
-                               dev_err(&urb->dev->dev,
-                                       "%s - failed resubmitting write urb, error %d\n",
-                                       __func__, result);
-                       else
-                               return;
        }
 
        port->write_urb_busy = 0;
@@ -472,11 +474,11 @@ static void aircable_read_bulk_callback(struct urb *urb)
                        dbg("%s - caught -EPROTO, resubmitting the urb",
                            __func__);
                        usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-                                         usb_rcvbulkpipe(port->serial->dev,
-                                                         port->bulk_in_endpointAddress),
-                                         port->read_urb->transfer_buffer,
-                                         port->read_urb->transfer_buffer_length,
-                                         aircable_read_bulk_callback, port);
+                               usb_rcvbulkpipe(port->serial->dev,
+                                       port->bulk_in_endpointAddress),
+                               port->read_urb->transfer_buffer,
+                               port->read_urb->transfer_buffer_length,
+                               aircable_read_bulk_callback, port);
 
                        result = usb_submit_urb(urb, GFP_ATOMIC);
                        if (result)
@@ -490,7 +492,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
        }
 
        usb_serial_debug_data(debug, &port->dev, __func__,
-                               urb->actual_length,urb->transfer_buffer);
+                               urb->actual_length, urb->transfer_buffer);
 
        tty = port->tty;
        if (tty && urb->actual_length) {
@@ -507,9 +509,9 @@ static void aircable_read_bulk_callback(struct urb *urb)
                        no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
 
                        if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
-                               no_packages+=1;
+                               no_packages++;
 
-                       for (i = 0; i < no_packages ;i++) {
+                       for (i = 0; i < no_packagesi++) {
                                if (remaining > (HCI_COMPLETE_FRAME))
                                        package_length = HCI_COMPLETE_FRAME;
                                else
@@ -529,7 +531,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
        if (port->open_count) {
                usb_fill_bulk_urb(port->read_urb, port->serial->dev,
                                  usb_rcvbulkpipe(port->serial->dev,
-                                                 port->bulk_in_endpointAddress),
+                                         port->bulk_in_endpointAddress),
                                  port->read_urb->transfer_buffer,
                                  port->read_urb->transfer_buffer_length,
                                  aircable_read_bulk_callback, port);
@@ -602,7 +604,7 @@ static struct usb_serial_driver aircable_device = {
        .unthrottle =           aircable_unthrottle,
 };
 
-static int __init aircable_init (void)
+static int __init aircable_init(void)
 {
        int retval;
        retval = usb_serial_register(&aircable_device);
@@ -619,7 +621,7 @@ failed_usb_register:
        return retval;
 }
 
-static void __exit aircable_exit (void)
+static void __exit aircable_exit(void)
 {
        usb_deregister(&aircable_driver);
        usb_serial_deregister(&aircable_device);
index 725b6b94c2740c2f0c58743caeca428c11cccc28..0798c14ce787767718e216b000cc8e6aef10c5ed 100644 (file)
@@ -68,8 +68,9 @@ static int airprime_send_setup(struct usb_serial_port *port)
                        val |= 0x02;
 
                return usb_control_msg(serial->dev,
-                               usb_rcvctrlpipe(serial->dev, 0),
-                               0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+                                       usb_rcvctrlpipe(serial->dev, 0),
+                                       0x22, 0x21, val, 0, NULL, 0,
+                                       USB_CTRL_SET_TIMEOUT);
        }
 
        return 0;
@@ -90,17 +91,19 @@ static void airprime_read_bulk_callback(struct urb *urb)
                    __func__, status);
                return;
        }
-       usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
+       usb_serial_debug_data(debug, &port->dev, __func__,
+                                               urb->actual_length, data);
 
        tty = port->tty;
        if (tty && urb->actual_length) {
-               tty_insert_flip_string (tty, data, urb->actual_length);
-               tty_flip_buffer_push (tty);
+               tty_insert_flip_string(tty, data, urb->actual_length);
+               tty_flip_buffer_push(tty);
        }
 
-       result = usb_submit_urb (urb, GFP_ATOMIC);
+       result = usb_submit_urb(urb, GFP_ATOMIC);
        if (result)
-               dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+               dev_err(&port->dev,
+                       "%s - failed resubmitting read urb, error %d\n",
                        __func__, result);
        return;
 }
@@ -115,7 +118,7 @@ static void airprime_write_bulk_callback(struct urb *urb)
        dbg("%s - port %d", __func__, port->number);
 
        /* free up the transfer buffer, as usb_free_urb() does not do this */
-       kfree (urb->transfer_buffer);
+       kfree(urb->transfer_buffer);
 
        if (status)
                dbg("%s - nonzero write bulk status received: %d",
@@ -171,7 +174,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
                }
                usb_fill_bulk_urb(urb, serial->dev,
                                  usb_rcvbulkpipe(serial->dev,
-                                                 port->bulk_out_endpointAddress),
+                                         port->bulk_out_endpointAddress),
                                  buffer, buffer_size,
                                  airprime_read_bulk_callback, port);
                result = usb_submit_urb(urb, GFP_KERNEL);
@@ -183,7 +186,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
                                __func__, i, port->number, result);
                        goto errout;
                }
-               /* remember this urb so we can kill it when the port is closed */
+               /* remember this urb so we can kill it when the
+                  port is closed */
                priv->read_urbp[i] = urb;
        }
 
@@ -192,22 +196,22 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
        goto out;
 
  errout:
-       /* some error happened, cancel any submitted urbs and clean up anything that
-          got allocated successfully */
+       /* some error happened, cancel any submitted urbs and clean up
+          anything that got allocated successfully */
 
        while (i-- != 0) {
                urb = priv->read_urbp[i];
                buffer = urb->transfer_buffer;
-               usb_kill_urb (urb);
-               usb_free_urb (urb);
-               kfree (buffer);
+               usb_kill_urb(urb);
+               usb_free_urb(urb);
+               kfree(buffer);
        }
 
  out:
        return result;
 }
 
-static void airprime_close(struct usb_serial_port *port, struct file * filp)
+static void airprime_close(struct usb_serial_port *port, struct file *filp)
 {
        struct airprime_private *priv = usb_get_serial_port_data(port);
        int i;
@@ -220,16 +224,16 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
        mutex_lock(&port->serial->disc_mutex);
        if (!port->serial->disconnected)
                airprime_send_setup(port);
-       mutex_lock(&port->serial->disc_mutex);
+       mutex_unlock(&port->serial->disc_mutex);
 
        for (i = 0; i < NUM_READ_URBS; ++i) {
-               usb_kill_urb (priv->read_urbp[i]);
-               kfree (priv->read_urbp[i]->transfer_buffer);
-               usb_free_urb (priv->read_urbp[i]);
+               usb_kill_urb(priv->read_urbp[i]);
+               kfree(priv->read_urbp[i]->transfer_buffer);
+               usb_free_urb(priv->read_urbp[i]);
        }
 
        /* free up private structure */
-       kfree (priv);
+       kfree(priv);
        usb_set_serial_port_data(port, NULL);
 }
 
@@ -259,10 +263,10 @@ static int airprime_write(struct usb_serial_port *port,
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
                dev_err(&port->dev, "no more free urbs\n");
-               kfree (buffer);
+               kfree(buffer);
                return -ENOMEM;
        }
-       memcpy (buffer, buf, count);
+       memcpy(buffer, buf, count);
 
        usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
 
@@ -279,7 +283,7 @@ static int airprime_write(struct usb_serial_port *port,
                        "%s - usb_submit_urb(write bulk) failed with status = %d\n",
                        __func__, status);
                count = status;
-               kfree (buffer);
+               kfree(buffer);
        } else {
                spin_lock_irqsave(&priv->lock, flags);
                ++priv->outstanding_urbs;
@@ -287,7 +291,7 @@ static int airprime_write(struct usb_serial_port *port,
        }
        /* we are done with this urb, so let the host driver
         * really free it when it is finished with it */
-       usb_free_urb (urb);
+       usb_free_urb(urb);
        return count;
 }
 
@@ -315,8 +319,10 @@ static int __init airprime_init(void)
 {
        int retval;
 
-       airprime_device.num_ports =
-               (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
+       airprime_device.num_ports = endpoints;
+       if (endpoints < 0 || endpoints >= MAX_BULK_EPS)
+               airprime_device.num_ports = NUM_BULK_EPS;
+
        retval = usb_serial_register(&airprime_device);
        if (retval)
                return retval;
@@ -341,6 +347,7 @@ MODULE_LICENSE("GPL");
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled");
 module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
+MODULE_PARM_DESC(buffer_size,
+               "Size of the transfer buffers in bytes (default 4096)");
 module_param(endpoints, int, 0);
 MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
index 599ab2e548a7c3e483abc255471ee5b92838c90e..77895c8f8f3189fb774acb59cad0f3f3a324cbad 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/serial.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 
 static int debug;
@@ -246,29 +246,29 @@ static void ark3116_set_termios(struct usb_serial_port *port,
        baud = tty_get_baud_rate(port->tty);
 
        switch (baud) {
-               case 75:
-               case 150:
-               case 300:
-               case 600:
-               case 1200:
-               case 1800:
-               case 2400:
-               case 4800:
-               case 9600:
-               case 19200:
-               case 38400:
-               case 57600:
-               case 115200:
-               case 230400:
-               case 460800:
-                       /* Report the resulting rate back to the caller */
-                       tty_encode_baud_rate(port->tty, baud, baud);
-                       break;
-               /* set 9600 as default (if given baudrate is invalid for example) */
-               default:
-                       tty_encode_baud_rate(port->tty, 9600, 9600);
-               case 0:
-                       baud = 9600;
+       case 75:
+       case 150:
+       case 300:
+       case 600:
+       case 1200:
+       case 1800:
+       case 2400:
+       case 4800:
+       case 9600:
+       case 19200:
+       case 38400:
+       case 57600:
+       case 115200:
+       case 230400:
+       case 460800:
+               /* Report the resulting rate back to the caller */
+               tty_encode_baud_rate(port->tty, baud, baud);
+               break;
+       /* set 9600 as default (if given baudrate is invalid for example) */
+       default:
+               tty_encode_baud_rate(port->tty, 9600, 9600);
+       case 0:
+               baud = 9600;
        }
 
        /*
@@ -380,19 +380,19 @@ static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
        switch (cmd) {
        case TIOCGSERIAL:
                /* XXX: Some of these values are probably wrong. */
-               memset(&serstruct, 0, sizeof (serstruct));
+               memset(&serstruct, 0, sizeof(serstruct));
                serstruct.type = PORT_16654;
                serstruct.line = port->serial->minor;
                serstruct.port = port->number;
                serstruct.custom_divisor = 0;
                serstruct.baud_base = 460800;
 
-               if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
+               if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
                        return -EFAULT;
 
                return 0;
        case TIOCSSERIAL:
-               if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
+               if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
                        return -EFAULT;
                return 0;
        default:
index d947d955bceb9504d9beae2d9877ddb41c105e28..ba28fdc9ccd2f589a2ec5038616dc91795fd9757 100644 (file)
@@ -130,7 +130,7 @@ static int ch341_get_status(struct usb_device *dev)
                return -ENOMEM;
 
        r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
-       if ( r < 0)
+       if (r < 0)
                goto out;
 
        /* Not having the datasheet for the CH341, we ignore the bytes returned
index c7329f43d9c9dc885fd65cb21ed80b29b4938162..5b349ece724744ac8358063ee53733e7d824a0be 100644 (file)
@@ -133,6 +133,14 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
index 6da539ede0ee992185ccb4b789b28f485bc39024..504edf8c3a3f1a32efdabdcffef0dfea76ddd018 100644 (file)
 /* AlphaMicro Components AMC-232USB01 device */
 #define FTDI_AMC232_PID 0xFF00 /* Product Id */
 
+/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
+/* the VID is the standard ftdi vid (FTDI_VID) */
+#define FTDI_SCS_DEVICE_0_PID 0xD010    /* SCS PTC-IIusb */
+#define FTDI_SCS_DEVICE_1_PID 0xD011    /* SCS Tracker / DSP TNC */
+#define FTDI_SCS_DEVICE_2_PID 0xD012
+#define FTDI_SCS_DEVICE_3_PID 0xD013
+#define FTDI_SCS_DEVICE_4_PID 0xD014
+#define FTDI_SCS_DEVICE_5_PID 0xD015
+#define FTDI_SCS_DEVICE_6_PID 0xD016
+#define FTDI_SCS_DEVICE_7_PID 0xD017
+
 /* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
 #define FTDI_ACTZWAVE_PID      0xF2D0
 
index 6bcb82d3911a7baf386c0eda874cf3ea68ab1ba5..78f2f6db494d790fb4d00d75c0ef9c1229ef89ef 100644 (file)
@@ -1713,7 +1713,7 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
 {
        struct moschip_port *mos7840_port;
        unsigned int mcr;
-       unsigned int status;
+       int status;
 
        dbg("%s - port %d", __func__, port->number);
 
@@ -1740,11 +1740,10 @@ static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
 
        mos7840_port->shadowMCR = mcr;
 
-       status = 0;
        status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
        if (status < 0) {
                dbg("setting MODEM_CONTROL_REGISTER Failed\n");
-               return -1;
+               return status;
        }
 
        return 0;
index 0f6d234d699b1327b2691ebca03f2a2707fe43a1..3d9249632ae12e7051174817241ef37ea6f2cd4c 100644 (file)
@@ -123,7 +123,8 @@ config USB_STORAGE_ALAUDA
 
 config USB_STORAGE_ONETOUCH
        bool "Support OneTouch Button on Maxtor Hard Drives"
-       depends on USB_STORAGE && INPUT_EVDEV
+       depends on USB_STORAGE
+       depends on INPUT=y || INPUT=USB_STORAGE
        help
          Say Y here to include additional code to support the Maxtor OneTouch
          USB hard drive's onetouch button.
index d88824b3511c0de74a320a0be30554052d374f7f..898e67d30e563bfc4b8a11cf1715cee5a1edec56 100644 (file)
@@ -46,7 +46,7 @@ void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
        }
 
        memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
-       memset(srb->cmnd, 0, sizeof(srb->cmnd));
+       memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
 
        /* check if we support the command */
        if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
index 971d13dd5e65a55e9256c932d63bc6b0a0caa1e4..3addcd8f827bd3d17463dbc67395c072cfae4d81 100644 (file)
@@ -292,6 +292,7 @@ struct isd200_info {
 
        /* maximum number of LUNs supported */
        unsigned char MaxLUNs;
+       unsigned char cmnd[BLK_MAX_CDB];
        struct scsi_cmnd srb;
        struct scatterlist sg;
 };
@@ -450,6 +451,7 @@ static int isd200_action( struct us_data *us, int action,
 
        memset(&ata, 0, sizeof(ata));
        memset(&srb_dev, 0, sizeof(srb_dev));
+       srb->cmnd = info->cmnd;
        srb->device = &srb_dev;
        ++srb->serial_number;
 
index a28d49122e7a046301799edfade54e95f50d1cdd..d617e8ae6b006b6d0b014774d86eb78bd1c9c6e3 100644 (file)
@@ -135,7 +135,7 @@ static int usu_probe(struct usb_interface *intf,
        stat[type].fls |= USU_MOD_FL_THREAD;
        spin_unlock_irqrestore(&usu_lock, flags);
 
-       task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
+       task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
        if (IS_ERR(task)) {
                rc = PTR_ERR(task);
                printk(KERN_WARNING "libusual: "
index dfd42fe9e5f0567d27e009f5514ab5a70d742b97..98b89ea9e3123bd94fac382fd4da32803b0280a9 100644 (file)
@@ -38,7 +38,7 @@
 #include "onetouch.h"
 #include "debug.h"
 
-void onetouch_release_input(void *onetouch_);
+static void onetouch_release_input(void *onetouch_);
 
 struct usb_onetouch {
        char name[128];
@@ -223,7 +223,7 @@ int onetouch_connect_input(struct us_data *ss)
        return error;
 }
 
-void onetouch_release_input(void *onetouch_)
+static void onetouch_release_input(void *onetouch_)
 {
        struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
 
index 732bf52a775e743d0039601b54dd20a127d00040..a0ed889230aa324124575307151d34a6ceb9d09e 100644 (file)
@@ -44,7 +44,8 @@
  *       running with this patch.
  * Send your submission to either Phil Dibowitz <phil@ipom.com> or
  * Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
- * USB development list <linux-usb-devel@lists.sourceforge.net>.
+ * USB development list <linux-usb@vger.kernel.org> and the USB storage list
+ * <usb-storage@lists.one-eyed-alien.net>
  */
 
 /* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
@@ -557,6 +558,13 @@ UNUSUAL_DEV(  0x04e6, 0x1010, 0x0000, 0x9999,
                US_FL_SINGLE_LUN),
 #endif
 
+/* Reported by Dmitry Khlystov <adminimus@gmail.com> */
+UNUSUAL_DEV(  0x04e8, 0x507c, 0x0220, 0x0220,
+               "Samsung",
+               "YP-U3",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64),
+
 /* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
 UNUSUAL_DEV(  0x050d, 0x0115, 0x0133, 0x0133,
                "Belkin",
@@ -1200,6 +1208,17 @@ UNUSUAL_DEV(  0x084d, 0x0011, 0x0110, 0x0110,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_BULK32),
 
+/* Andrew Lunn <andrew@lunn.ch>
+ * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
+ * on LUN 4.
+ * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
+*/
+UNUSUAL_DEV(  0x0851, 0x1543, 0x0200, 0x0200,
+               "PanDigital",
+               "Photo Frame",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_NOT_LOCKABLE),
+
 /* Submitted by Jan De Luyck <lkml@kcore.org> */
 UNUSUAL_DEV(  0x08bd, 0x1100, 0x0000, 0x0000,
                "CITIZEN",
@@ -1342,6 +1361,13 @@ UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_INQUIRY),
 
+/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
+UNUSUAL_DEV(  0x2770, 0x915d, 0x0010, 0x0010,
+               "INTOVA",
+               "Pixtreme",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY ),
+
 /*
  * Entry for Jenoptik JD 5200z3
  *
index a856effad3bde74c9707bce6e9ff2dfe96681009..e268aacb773a57e5041aac509389543b853614a0 100644 (file)
@@ -539,7 +539,8 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
                                " has %s in unusual_devs.h (kernel"
                                " %s)\n"
                                "   Please send a copy of this message to "
-                               "<linux-usb-devel@lists.sourceforge.net>\n",
+                               "<linux-usb@vger.kernel.org> and "
+                               "<usb-storage@lists.one-eyed-alien.net>\n",
                                le16_to_cpu(ddesc->idVendor),
                                le16_to_cpu(ddesc->idProduct),
                                le16_to_cpu(ddesc->bcdDevice),
index b535483bc556f5f153eb434583c8dc6593377164..13866789b3561027b803797a95c985f573671fd4 100644 (file)
@@ -80,19 +80,51 @@ static void add_status(struct virtio_device *dev, unsigned status)
        dev->config->set_status(dev, dev->config->get_status(dev) | status);
 }
 
+void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
+                                        unsigned int fbit)
+{
+       unsigned int i;
+       struct virtio_driver *drv = container_of(vdev->dev.driver,
+                                                struct virtio_driver, driver);
+
+       for (i = 0; i < drv->feature_table_size; i++)
+               if (drv->feature_table[i] == fbit)
+                       return;
+       BUG();
+}
+EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
+
 static int virtio_dev_probe(struct device *_d)
 {
-       int err;
+       int err, i;
        struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
        struct virtio_driver *drv = container_of(dev->dev.driver,
                                                 struct virtio_driver, driver);
+       u32 device_features;
 
+       /* We have a driver! */
        add_status(dev, VIRTIO_CONFIG_S_DRIVER);
+
+       /* Figure out what features the device supports. */
+       device_features = dev->config->get_features(dev);
+
+       /* Features supported by both device and driver into dev->features. */
+       memset(dev->features, 0, sizeof(dev->features));
+       for (i = 0; i < drv->feature_table_size; i++) {
+               unsigned int f = drv->feature_table[i];
+               BUG_ON(f >= 32);
+               if (device_features & (1 << f))
+                       set_bit(f, dev->features);
+       }
+
        err = drv->probe(dev);
        if (err)
                add_status(dev, VIRTIO_CONFIG_S_FAILED);
-       else
+       else {
                add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+               /* They should never have set feature bits beyond 32 */
+               dev->config->set_features(dev, dev->features[0]);
+       }
        return err;
 }
 
@@ -114,6 +146,8 @@ static int virtio_dev_remove(struct device *_d)
 
 int register_virtio_driver(struct virtio_driver *driver)
 {
+       /* Catch this early. */
+       BUG_ON(driver->feature_table_size && !driver->feature_table);
        driver->driver.bus = &virtio_bus;
        driver->driver.probe = virtio_dev_probe;
        driver->driver.remove = virtio_dev_remove;
index 0b3efc31ee6d38620f97855a8c2d4941eea5f5b9..bfef604160d16460062f46b84f16c9320579c0d4 100644 (file)
@@ -155,9 +155,9 @@ static void virtballoon_changed(struct virtio_device *vdev)
 static inline s64 towards_target(struct virtio_balloon *vb)
 {
        u32 v;
-       __virtio_config_val(vb->vdev,
-                           offsetof(struct virtio_balloon_config, num_pages),
-                           &v);
+       vb->vdev->config->get(vb->vdev,
+                             offsetof(struct virtio_balloon_config, num_pages),
+                             &v, sizeof(v));
        return v - vb->num_pages;
 }
 
@@ -227,7 +227,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
        }
 
        vb->tell_host_first
-               = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+               = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
 
        return 0;
 
@@ -259,7 +259,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
        kfree(vb);
 }
 
+static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+
 static struct virtio_driver virtio_balloon = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
index c0df924766a7ea0daaf0bfa46ad5df4c06a2adc8..27e9fc9117cdfa69fee88e32e3636a844d803d5e 100644 (file)
@@ -87,23 +87,22 @@ static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
        return container_of(vdev, struct virtio_pci_device, vdev);
 }
 
-/* virtio config->feature() implementation */
-static bool vp_feature(struct virtio_device *vdev, unsigned bit)
+/* virtio config->get_features() implementation */
+static u32 vp_get_features(struct virtio_device *vdev)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+       /* When someone needs more than 32 feature bits, we'll need to
+        * steal a bit to indicate that the rest are somewhere else. */
+       return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+/* virtio config->set_features() implementation */
+static void vp_set_features(struct virtio_device *vdev, u32 features)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-       u32 mask;
-
-       /* Since this function is supposed to have the side effect of
-        * enabling a queried feature, we simulate that by doing a read
-        * from the host feature bitmask and then writing to the guest
-        * feature bitmask */
-       mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
-       if (mask & (1 << bit)) {
-               mask |= (1 << bit);
-               iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
-       }
 
-       return !!(mask & (1 << bit));
+       iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
 }
 
 /* virtio config->get() implementation */
@@ -145,14 +144,14 @@ static void vp_set_status(struct virtio_device *vdev, u8 status)
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        /* We should never be setting status to 0. */
        BUG_ON(status == 0);
-       return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+       iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
 }
 
 static void vp_reset(struct virtio_device *vdev)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        /* 0 status means a reset. */
-       return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+       iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
 }
 
 /* the notify function used when creating a virt queue */
@@ -293,7 +292,6 @@ static void vp_del_vq(struct virtqueue *vq)
 }
 
 static struct virtio_config_ops virtio_pci_config_ops = {
-       .feature        = vp_feature,
        .get            = vp_get,
        .set            = vp_set,
        .get_status     = vp_get_status,
@@ -301,6 +299,8 @@ static struct virtio_config_ops virtio_pci_config_ops = {
        .reset          = vp_reset,
        .find_vq        = vp_find_vq,
        .del_vq         = vp_del_vq,
+       .get_features   = vp_get_features,
+       .set_features   = vp_set_features,
 };
 
 /* the PCI probing function */
index c2fa5c6308133e5bd9c4e4c39e4a6c0b9b8b7c4b..937a49d6772cc5271d22ef48cb14df6bf56c07f7 100644 (file)
@@ -184,6 +184,11 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
 
        START_USE(vq);
 
+       if (unlikely(vq->broken)) {
+               END_USE(vq);
+               return NULL;
+       }
+
        if (!more_used(vq)) {
                pr_debug("No more buffers in queue\n");
                END_USE(vq);
index f42be069e085b2d212b8cc633d61f418be6801f5..977ef208c05193bbe555a4b4bce50853f0483616 100644 (file)
@@ -57,9 +57,6 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
  *                    anonymous inode, and a dentry that describe the "class"
  *                    of the file
  *
- * @pfd:     [out]   pointer to the file descriptor
- * @dpinode: [out]   pointer to the inode
- * @pfile:   [out]   pointer to the file struct
  * @name:    [in]    name of the "class" of the new file
  * @fops     [in]    file operations for the new file
  * @priv     [in]    private data for the new file (will be file's private_data)
@@ -68,10 +65,9 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
  * that do not need to have a full-fledged inode in order to operate correctly.
  * All the files created with anon_inode_getfd() will share a single inode,
  * hence saving memory and avoiding code duplication for the file/inode/dentry
- * setup.
+ * setup.  Returns new descriptor or -error.
  */
-int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
-                    const char *name, const struct file_operations *fops,
+int anon_inode_getfd(const char *name, const struct file_operations *fops,
                     void *priv)
 {
        struct qstr this;
@@ -125,10 +121,7 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
 
        fd_install(fd, file);
 
-       *pfd = fd;
-       *pinode = anon_inode_inode;
-       *pfile = file;
-       return 0;
+       return fd;
 
 err_dput:
        dput(dentry);
index d96e5c14a9caaaaa2c498b3e5f833176634e3b14..894fee54d4d83bd1ce22c50817871f1dc8c6f0da 100644 (file)
@@ -73,8 +73,8 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
        status = 0;
 done:
        DPRINTK("returning = %d", status);
-       mntput(mnt);
        dput(dentry);
+       mntput(mnt);
        return status;
 }
 
@@ -333,7 +333,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
                        /* Can we expire this guy */
                        if (autofs4_can_expire(dentry, timeout, do_now)) {
                                expired = dentry;
-                               break;
+                               goto found;
                        }
                        goto next;
                }
@@ -352,7 +352,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
                                inf->flags |= AUTOFS_INF_EXPIRING;
                                spin_unlock(&sbi->fs_lock);
                                expired = dentry;
-                               break;
+                               goto found;
                        }
                        spin_unlock(&sbi->fs_lock);
                /*
@@ -363,7 +363,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
                        expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
                        if (expired) {
                                dput(dentry);
-                               break;
+                               goto found;
                        }
                }
 next:
@@ -371,18 +371,16 @@ next:
                spin_lock(&dcache_lock);
                next = next->next;
        }
-
-       if (expired) {
-               DPRINTK("returning %p %.*s",
-                       expired, (int)expired->d_name.len, expired->d_name.name);
-               spin_lock(&dcache_lock);
-               list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
-               spin_unlock(&dcache_lock);
-               return expired;
-       }
        spin_unlock(&dcache_lock);
-
        return NULL;
+
+found:
+       DPRINTK("returning %p %.*s",
+               expired, (int)expired->d_name.len, expired->d_name.name);
+       spin_lock(&dcache_lock);
+       list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+       spin_unlock(&dcache_lock);
+       return expired;
 }
 
 /* Perform an expiry operation */
index aa4c5ff8a40dfcf65babdd56c9e6fac056b4423f..edf5b6bddb528a43bb85e51eb834ecbdb14a7877 100644 (file)
@@ -146,17 +146,17 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
 
        if (d_mountpoint(dentry)) {
                struct file *fp = NULL;
-               struct vfsmount *fp_mnt = mntget(mnt);
-               struct dentry *fp_dentry = dget(dentry);
+               struct path fp_path = { .dentry = dentry, .mnt = mnt };
 
-               if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
-                       dput(fp_dentry);
-                       mntput(fp_mnt);
+               path_get(&fp_path);
+
+               if (!autofs4_follow_mount(&fp_path.mnt, &fp_path.dentry)) {
+                       path_put(&fp_path);
                        dcache_dir_close(inode, file);
                        goto out;
                }
 
-               fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
+               fp = dentry_open(fp_path.dentry, fp_path.mnt, file->f_flags);
                status = PTR_ERR(fp);
                if (IS_ERR(fp)) {
                        dcache_dir_close(inode, file);
@@ -242,7 +242,8 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
-       int status = 0;
+       struct dentry *new;
+       int status;
 
        /* Block on any pending expiry here; invalidate the dentry
            when expiration is done to trigger mount request with a new
@@ -318,7 +319,28 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
        spin_lock(&dentry->d_lock);
        dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
        spin_unlock(&dentry->d_lock);
-       return status;
+
+       /*
+        * The dentry that is passed in from lookup may not be the one
+        * we end up using, as mkdir can create a new one.  If this
+        * happens, and another process tries the lookup at the same time,
+        * it will set the PENDING flag on this new dentry, but add itself
+        * to our waitq.  Then, if after the lookup succeeds, the first
+        * process that requested the mount performs another lookup of the
+        * same directory, it will show up as still pending!  So, we need
+        * to redo the lookup here and clear pending on that dentry.
+        */
+       if (d_unhashed(dentry)) {
+               new = d_lookup(dentry->d_parent, &dentry->d_name);
+               if (new) {
+                       spin_lock(&new->d_lock);
+                       new->d_flags &= ~DCACHE_AUTOFS_PENDING;
+                       spin_unlock(&new->d_lock);
+                       dput(new);
+               }
+       }
+
+       return 0;
 }
 
 /* For autofs direct mounts the follow link triggers the mount */
index 1fe28e4754c2c7b44fc3516d4f633bc1c8d4351c..75e5955c3f6d4fe5cf30b3ffcc3d6bc21a9fbffb 100644 (file)
@@ -171,7 +171,7 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,
        for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
                len += tmp->d_name.len + 1;
 
-       if (--len > NAME_MAX) {
+       if (!len || --len > NAME_MAX) {
                spin_unlock(&dcache_lock);
                return 0;
        }
index 139dc93c092d697b10d540a12020bd92e2e84b41..332a869d2c53e80a6bfb75c5e2bd3009802eca58 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fcntl.h>
 #include <linux/namei.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/vfs.h>
 #include <linux/ioctl.h>
 #include <linux/init.h>
index fddffe4851f550cd78315189d6466bc0a24ad126..159a5efd6a8a8bcf43ecf0b637023bb3d11e24d4 100644 (file)
@@ -9,7 +9,7 @@
  *     2 as published by the Free Software Foundation.
  *
  *  debugfs is for people to use instead of /proc or /sys.
- *  See Documentation/DocBook/kernel-api for more details.
+ *  See Documentation/DocBook/filesystems for more details.
  *
  */
 
index 28d01ed66de0198130407a9d36411f77946cd1c7..676073b8dda57659202b123dde8adb90e0fb416b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
+#include <linux/fdtable.h>
 
 int dir_notify_enable __read_mostly = 1;
 
@@ -66,6 +67,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
        struct dnotify_struct **prev;
        struct inode *inode;
        fl_owner_t id = current->files;
+       struct file *f;
        int error = 0;
 
        if ((arg & ~DN_MULTISHOT) == 0) {
@@ -92,6 +94,15 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
                prev = &odn->dn_next;
        }
 
+       rcu_read_lock();
+       f = fcheck(fd);
+       rcu_read_unlock();
+       /* we'd lost the race with close(), sod off silently */
+       /* note that inode->i_lock prevents reordering problems
+        * between accesses to descriptor table and ->i_dnotify */
+       if (f != filp)
+               goto out_free;
+
        error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
        if (error)
                goto out_free;
index a9f130cd50ac2be6009ed2091fce0ec21d134fdd..343942deeec138b1925e7815d0ac819e41f1214e 100644 (file)
@@ -200,10 +200,8 @@ struct file *eventfd_fget(int fd)
 
 asmlinkage long sys_eventfd(unsigned int count)
 {
-       int error, fd;
+       int fd;
        struct eventfd_ctx *ctx;
-       struct file *file;
-       struct inode *inode;
 
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
@@ -216,12 +214,9 @@ asmlinkage long sys_eventfd(unsigned int count)
         * When we call this, the initialization must be complete, since
         * anon_inode_getfd() will install the fd.
         */
-       error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]",
-                                &eventfd_fops, ctx);
-       if (!error)
-               return fd;
-
-       kfree(ctx);
-       return error;
+       fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx);
+       if (fd < 0)
+               kfree(ctx);
+       return fd;
 }
 
index 221086fef1743545c143a270bd1bc228cfb33561..990c01d2d66bcce64a1c2a993cd6cc01ea5951d5 100644 (file)
@@ -1050,8 +1050,6 @@ asmlinkage long sys_epoll_create(int size)
 {
        int error, fd = -1;
        struct eventpoll *ep;
-       struct inode *inode;
-       struct file *file;
 
        DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
                     current, size));
@@ -1061,29 +1059,24 @@ asmlinkage long sys_epoll_create(int size)
         * structure ( "struct eventpoll" ).
         */
        error = -EINVAL;
-       if (size <= 0 || (error = ep_alloc(&ep)) != 0)
+       if (size <= 0 || (error = ep_alloc(&ep)) < 0) {
+               fd = error;
                goto error_return;
+       }
 
        /*
         * Creates all the items needed to setup an eventpoll file. That is,
-        * a file structure, and inode and a free file descriptor.
+        * a file structure and a free file descriptor.
         */
-       error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]",
-                                &eventpoll_fops, ep);
-       if (error)
-               goto error_free;
+       fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep);
+       if (fd < 0)
+               ep_free(ep);
 
+error_return:
        DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
                     current, size, fd));
 
        return fd;
-
-error_free:
-       ep_free(ep);
-error_return:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
-                    current, size, error));
-       return error;
 }
 
 /*
index 9f9f931ef949987e29ba89204387c1428e491c66..aeaa9791d8be2ed499aea2c314d939f385d76e54 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -24,6 +24,7 @@
 
 #include <linux/slab.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/mman.h>
 #include <linux/a.out.h>
 #include <linux/stat.h>
index 3f3ac630ccde701992caf5edf69a5f717c424f0c..bfd776509a7271e324c5559397542c36c4564a34 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/capability.h>
 #include <linux/dnotify.h>
 #include <linux/smp_lock.h>
index 5110acb1c9ef59bb046a69f79fa601a07218b61a..4c6f0ea12c419c52154558c271586b7887dabf13 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
@@ -149,8 +150,16 @@ 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 > sysctl_nr_open)
-               nr = sysctl_nr_open;
+       /*
+        * Note that this can drive nr *below* what we had passed if sysctl_nr_open
+        * had been set lower between the check in expand_files() and here.  Deal
+        * with that in caller, it's cheaper that way.
+        *
+        * We make sure that nr remains a multiple of BITS_PER_LONG - otherwise
+        * bitmaps handling below becomes unpleasant, to put it mildly...
+        */
+       if (unlikely(nr > sysctl_nr_open))
+               nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;
 
        fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
        if (!fdt)
@@ -198,6 +207,16 @@ static int expand_fdtable(struct files_struct *files, int nr)
        spin_lock(&files->file_lock);
        if (!new_fdt)
                return -ENOMEM;
+       /*
+        * extremely unlikely race - sysctl_nr_open decreased between the check in
+        * caller and alloc_fdtable().  Cheaper to catch it here...
+        */
+       if (unlikely(new_fdt->max_fds <= nr)) {
+               free_fdarr(new_fdt);
+               free_fdset(new_fdt);
+               kfree(new_fdt);
+               return -EMFILE;
+       }
        /*
         * Check again since another task may have expanded the fd table while
         * we dropped the lock
index 7a0a9b8722513faae34fc0f145c06f241f2630f7..83084225b4c3b3195520d5a7a441360046d6f230 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/fs.h>
index 9ced35b006867e1445af3f9fe010906ac0684f87..f28cf8b46f806f89c595de8f746731032e625d0d 100644 (file)
@@ -934,7 +934,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
 
        nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
        npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ);
+       npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
        down_read(&current->mm->mmap_sem);
        npages = get_user_pages(current, current->mm, user_addr, npages, write,
                                0, req->pages, NULL);
index d58f845ccb85984666d2e6ef0d1d6d9339c10d67..c5e1450d79f9d311ea5e797554227230200db4c7 100644 (file)
@@ -46,7 +46,7 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
 
 
 static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
-                                       struct jffs2_inode_cache *ic)
+                                   struct jffs2_inode_cache *ic)
 {
        struct jffs2_full_dirent *fd;
 
@@ -68,11 +68,17 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
                        continue;
                }
 
-               if (child_ic->nlink++ && fd->type == DT_DIR) {
-                       JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
-                               fd->name, fd->ino, ic->ino);
-                       /* TODO: What do we do about it? */
-               }
+               if (fd->type == DT_DIR) {
+                       if (child_ic->pino_nlink) {
+                               JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
+                                           fd->name, fd->ino, ic->ino);
+                               /* TODO: What do we do about it? */
+                       } else {
+                               child_ic->pino_nlink = ic->ino;
+                       }
+               } else
+                       child_ic->pino_nlink++;
+
                dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
                /* Can't free scan_dents so far. We might need them in pass 2 */
        }
@@ -125,7 +131,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        dbg_fsbuild("pass 2 starting\n");
 
        for_each_inode(i, c, ic) {
-               if (ic->nlink)
+               if (ic->pino_nlink)
                        continue;
 
                jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
@@ -232,16 +238,19 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
                        /* Reduce nlink of the child. If it's now zero, stick it on the
                           dead_fds list to be cleaned up later. Else just free the fd */
 
-                       child_ic->nlink--;
+                       if (fd->type == DT_DIR)
+                               child_ic->pino_nlink = 0;
+                       else
+                               child_ic->pino_nlink--;
 
-                       if (!child_ic->nlink) {
-                               dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n",
+                       if (!child_ic->pino_nlink) {
+                               dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
                                          fd->ino, fd->name);
                                fd->next = *dead_fds;
                                *dead_fds = fd;
                        } else {
                                dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
-                                         fd->ino, fd->name, child_ic->nlink);
+                                         fd->ino, fd->name, child_ic->pino_nlink);
                                jffs2_free_full_dirent(fd);
                        }
                }
index c63e7a96af0dd025996c80b707b710213d7bdb1d..c0c141f6fde11c5e9367698494471e2462f181a3 100644 (file)
@@ -208,6 +208,13 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        f = JFFS2_INODE_INFO(inode);
        dir_f = JFFS2_INODE_INFO(dir_i);
 
+       /* jffs2_do_create() will want to lock it, _after_ reserving
+          space and taking c-alloc_sem. If we keep it locked here,
+          lockdep gets unhappy (although it's a false positive;
+          nothing else will be looking at this inode yet so there's
+          no chance of AB-BA deadlock involving its f->sem). */
+       mutex_unlock(&f->sem);
+
        ret = jffs2_do_create(c, dir_f, f, ri,
                              dentry->d_name.name, dentry->d_name.len);
        if (ret)
@@ -219,7 +226,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        d_instantiate(dentry, inode);
 
        D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
-                 inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
+                 inode->i_ino, inode->i_mode, inode->i_nlink,
+                 f->inocache->pino_nlink, inode->i_mapping->nrpages));
        return 0;
 
  fail:
@@ -243,7 +251,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
        ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
                              dentry->d_name.len, dead_f, now);
        if (dead_f->inocache)
-               dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+               dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
        if (!ret)
                dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
        return ret;
@@ -276,7 +284,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
 
        if (!ret) {
                mutex_lock(&f->sem);
-               old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
+               old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
                mutex_unlock(&f->sem);
                d_instantiate(dentry, old_dentry->d_inode);
                dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
@@ -493,11 +501,14 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
 
        inode->i_op = &jffs2_dir_inode_operations;
        inode->i_fop = &jffs2_dir_operations;
-       /* Directories get nlink 2 at start */
-       inode->i_nlink = 2;
 
        f = JFFS2_INODE_INFO(inode);
 
+       /* Directories get nlink 2 at start */
+       inode->i_nlink = 2;
+       /* but ic->pino_nlink is the parent ino# */
+       f->inocache->pino_nlink = dir_i->i_ino;
+
        ri->data_crc = cpu_to_je32(0);
        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
 
@@ -594,17 +605,25 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
 
 static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
 {
+       struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
+       struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
        struct jffs2_full_dirent *fd;
        int ret;
+       uint32_t now = get_seconds();
 
        for (fd = f->dents ; fd; fd = fd->next) {
                if (fd->ino)
                        return -ENOTEMPTY;
        }
-       ret = jffs2_unlink(dir_i, dentry);
-       if (!ret)
+
+       ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
+                             dentry->d_name.len, f, now);
+       if (!ret) {
+               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+               clear_nlink(dentry->d_inode);
                drop_nlink(dir_i);
+       }
        return ret;
 }
 
@@ -817,7 +836,10 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                   inode which didn't exist. */
                if (victim_f->inocache) {
                        mutex_lock(&victim_f->sem);
-                       victim_f->inocache->nlink--;
+                       if (S_ISDIR(new_dentry->d_inode->i_mode))
+                               victim_f->inocache->pino_nlink = 0;
+                       else
+                               victim_f->inocache->pino_nlink--;
                        mutex_unlock(&victim_f->sem);
                }
        }
@@ -838,8 +860,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
                mutex_lock(&f->sem);
                inc_nlink(old_dentry->d_inode);
-               if (f->inocache)
-                       f->inocache->nlink++;
+               if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
+                       f->inocache->pino_nlink++;
                mutex_unlock(&f->sem);
 
                printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
index 25a640e566d3d6d47ae9310b12b3e222f7bbed52..dddb2a6c9e2cfc087b6becc7f88d9e85ab1d02b4 100644 (file)
@@ -294,7 +294,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                        break;
 #endif
                default:
-                       if (ic->nodes == (void *)ic && ic->nlink == 0)
+                       if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
                                jffs2_del_ino_cache(c, ic);
        }
 }
@@ -332,7 +332,8 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
        if (c->mtd->point) {
                unsigned long *wordebuf;
 
-               ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf);
+               ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size,
+                                   &retlen, &ebuf, NULL);
                if (ret) {
                        D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
                        goto do_flash_read;
@@ -340,7 +341,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
                if (retlen < c->sector_size) {
                        /* Don't muck about if it won't let us point to the whole erase sector */
                        D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
-                       c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen);
+                       c->mtd->unpoint(c->mtd, jeb->offset, retlen);
                        goto do_flash_read;
                }
                wordebuf = ebuf-sizeof(*wordebuf);
@@ -349,7 +350,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
                   if (*++wordebuf != ~0)
                           break;
                } while(--retlen);
-               c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size);
+               c->mtd->unpoint(c->mtd, jeb->offset, c->sector_size);
                if (retlen) {
                        printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
                               *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
index 3eb1c84b0a33289b62dfef1dd21d774647302d64..086c4383022181f3624f333143daf9d5ddf99081 100644 (file)
@@ -273,7 +273,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
        inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
        inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
 
-       inode->i_nlink = f->inocache->nlink;
+       inode->i_nlink = f->inocache->pino_nlink;
 
        inode->i_blocks = (inode->i_size + 511) >> 9;
 
@@ -286,13 +286,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
        case S_IFDIR:
        {
                struct jffs2_full_dirent *fd;
+               inode->i_nlink = 2; /* parent and '.' */
 
                for (fd=f->dents; fd; fd = fd->next) {
                        if (fd->type == DT_DIR && fd->ino)
                                inc_nlink(inode);
                }
-               /* and '..' */
-               inc_nlink(inode);
                /* Root dir gets i_nlink 3 for some reason */
                if (inode->i_ino == 1)
                        inc_nlink(inode);
@@ -586,11 +585,12 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c,
 }
 
 struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
-                                                    int inum, int nlink)
+                                             int inum, int unlinked)
 {
        struct inode *inode;
        struct jffs2_inode_cache *ic;
-       if (!nlink) {
+
+       if (unlinked) {
                /* The inode has zero nlink but its nodes weren't yet marked
                   obsolete. This has to be because we're still waiting for
                   the final (close() and) iput() to happen.
@@ -638,8 +638,8 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
                        return ERR_CAST(inode);
        }
        if (is_bad_inode(inode)) {
-               printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
-                      inum, nlink);
+               printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. unlinked %d\n",
+                      inum, unlinked);
                /* NB. This will happen again. We need to do something appropriate here. */
                iput(inode);
                return ERR_PTR(-EIO);
index bad005664e308b1fd2f30e49ccad91d7afd57b91..090c556ffed28c7861b957efacf30099716ac465 100644 (file)
@@ -161,8 +161,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                        continue;
                }
 
-               if (!ic->nlink) {
-                       D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
+               if (!ic->pino_nlink) {
+                       D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink/pino zero\n",
                                  ic->ino));
                        spin_unlock(&c->inocache_lock);
                        jffs2_xattr_delete_inode(c, ic);
@@ -398,10 +398,10 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
           it's vaguely possible. */
 
        inum = ic->ino;
-       nlink = ic->nlink;
+       nlink = ic->pino_nlink;
        spin_unlock(&c->inocache_lock);
 
-       f = jffs2_gc_fetch_inode(c, inum, nlink);
+       f = jffs2_gc_fetch_inode(c, inum, !nlink);
        if (IS_ERR(f)) {
                ret = PTR_ERR(f);
                goto release_sem;
index 8219df6eb6d8c4191c78745c285272e5ce06f636..1750445556c313dbb9ddf716a52cce14fe6deac9 100644 (file)
@@ -177,7 +177,10 @@ struct jffs2_inode_cache {
 #ifdef CONFIG_JFFS2_FS_XATTR
        struct jffs2_xattr_ref *xref;
 #endif
-       int nlink;
+       uint32_t pino_nlink;    /* Directories store parent inode
+                                  here; other inodes store nlink.
+                                  Zero always means that it's
+                                  completely unlinked. */
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
index 9df8f3ef20dfd8d8a39d59ee02d4e14ea2713927..a9bf9603c1ba0cca4fac8d56ea2dae4bbfe33b91 100644 (file)
@@ -709,7 +709,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                                break;
 #endif
                        default:
-                               if (ic->nodes == (void *)ic && ic->nlink == 0)
+                               if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
                                        jffs2_del_ino_cache(c, ic);
                                break;
                }
index 1b10d2594092b87cf8505e9237e93f02abf09737..2cc866cf134f18ce26bbecdd9b70c450cc075906 100644 (file)
@@ -187,7 +187,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
 void jffs2_gc_release_inode(struct jffs2_sb_info *c,
                            struct jffs2_inode_info *f);
 struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
-                                             int inum, int nlink);
+                                             int inum, int unlinked);
 
 unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
                                   struct jffs2_inode_info *f,
index 4cb4d76de07f4810771e33edb6c8021d0a7896d1..6ca08ad887c09211bf98ab57cb1ec8578bd5d632 100644 (file)
@@ -63,10 +63,11 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
        /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
         * adding and jffs2_flash_read_end() interface. */
        if (c->mtd->point) {
-               err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
+               err = c->mtd->point(c->mtd, ofs, len, &retlen,
+                                   (void **)&buffer, NULL);
                if (!err && retlen < len) {
                        JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
-                       c->mtd->unpoint(c->mtd, buffer, ofs, retlen);
+                       c->mtd->unpoint(c->mtd, ofs, retlen);
                } else if (err)
                        JFFS2_WARNING("MTD point failed: error code %d.\n", err);
                else
@@ -100,7 +101,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
                kfree(buffer);
 #ifndef __ECOS
        else
-               c->mtd->unpoint(c->mtd, buffer, ofs, len);
+               c->mtd->unpoint(c->mtd, ofs, len);
 #endif
 
        if (crc != tn->data_crc) {
@@ -136,7 +137,7 @@ free_out:
                kfree(buffer);
 #ifndef __ECOS
        else
-               c->mtd->unpoint(c->mtd, buffer, ofs, len);
+               c->mtd->unpoint(c->mtd, ofs, len);
 #endif
        return err;
 }
@@ -1123,7 +1124,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
        size_t retlen;
        int ret;
 
-       dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);
+       dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino,
+                     f->inocache->pino_nlink);
 
        memset(&rii, 0, sizeof(rii));
 
@@ -1358,7 +1360,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                }
                dbg_readinode("creating inocache for root inode\n");
                memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
-               f->inocache->ino = f->inocache->nlink = 1;
+               f->inocache->ino = f->inocache->pino_nlink = 1;
                f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
                f->inocache->state = INO_STATE_READING;
                jffs2_add_ino_cache(c, f->inocache);
@@ -1401,7 +1403,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
        jffs2_clear_acl(f);
        jffs2_xattr_delete_inode(c, f->inocache);
        mutex_lock(&f->sem);
-       deleted = f->inocache && !f->inocache->nlink;
+       deleted = f->inocache && !f->inocache->pino_nlink;
 
        if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
                jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
index 272872d27fd53242cf50b487c330e112c4b59d06..1d437de1e9a8c1fa1aed3992571f8ed7c2e9bf7b 100644 (file)
@@ -97,11 +97,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        size_t pointlen;
 
        if (c->mtd->point) {
-               ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
+               ret = c->mtd->point(c->mtd, 0, c->mtd->size, &pointlen,
+                                   (void **)&flashbuf, NULL);
                if (!ret && pointlen < c->mtd->size) {
                        /* Don't muck about if it won't let us point to the whole flash */
                        D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
-                       c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen);
+                       c->mtd->unpoint(c->mtd, 0, pointlen);
                        flashbuf = NULL;
                }
                if (ret)
@@ -267,7 +268,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                kfree(flashbuf);
 #ifndef __ECOS
        else
-               c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
+               c->mtd->unpoint(c->mtd, 0, c->mtd->size);
 #endif
        if (s)
                kfree(s);
@@ -940,7 +941,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin
        ic->nodes = (void *)ic;
        jffs2_add_ino_cache(c, ic);
        if (ino == 1)
-               ic->nlink = 1;
+               ic->pino_nlink = 1;
        return ic;
 }
 
index f3353df178e707e8072e048e46b23753e5c88d5d..7da69eae49e491267699dcd8ca50535f5af15aed 100644 (file)
@@ -31,11 +31,12 @@ static struct kmem_cache *jffs2_inode_cachep;
 
 static struct inode *jffs2_alloc_inode(struct super_block *sb)
 {
-       struct jffs2_inode_info *ei;
-       ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
-       if (!ei)
+       struct jffs2_inode_info *f;
+
+       f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
+       if (!f)
                return NULL;
-       return &ei->vfs_inode;
+       return &f->vfs_inode;
 }
 
 static void jffs2_destroy_inode(struct inode *inode)
@@ -45,10 +46,10 @@ static void jffs2_destroy_inode(struct inode *inode)
 
 static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo)
 {
-       struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
+       struct jffs2_inode_info *f = foo;
 
-       mutex_init(&ei->sem);
-       inode_init_once(&ei->vfs_inode);
+       mutex_init(&f->sem);
+       inode_init_once(&f->vfs_inode);
 }
 
 static int jffs2_sync_fs(struct super_block *sb, int wait)
index 8de52b6076785816abf1625fbb2b64534a7c5610..0e78b00035e47a313ba43bafba87dfffbe9cf1b4 100644 (file)
@@ -494,7 +494,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
                                /* If it's an in-core inode, then we have to adjust any
                                   full_dirent or full_dnode structure to point to the
                                   new version instead of the old */
-                               f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink);
+                               f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink);
                                if (IS_ERR(f)) {
                                        /* Should never happen; it _must_ be present */
                                        JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
index 665fce9797d38d4569a92056f1391bdb5c0a9279..ca29440e9435867650514303b256c54528b8c1ef 100644 (file)
@@ -19,7 +19,8 @@
 #include "compr.h"
 
 
-int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                      uint32_t mode, struct jffs2_raw_inode *ri)
 {
        struct jffs2_inode_cache *ic;
 
@@ -31,7 +32,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
        memset(ic, 0, sizeof(*ic));
 
        f->inocache = ic;
-       f->inocache->nlink = 1;
+       f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */
        f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
        f->inocache->state = INO_STATE_PRESENT;
 
@@ -438,10 +439,10 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
        ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
                                JFFS2_SUMMARY_INODE_SIZE);
        D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
-       if (ret) {
-               mutex_unlock(&f->sem);
+       if (ret)
                return ret;
-       }
+
+       mutex_lock(&f->sem);
 
        ri->data_crc = cpu_to_je32(0);
        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
@@ -635,9 +636,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                                        jffs2_mark_node_obsolete(c, fd->raw);
                                jffs2_free_full_dirent(fd);
                        }
-               }
-
-               dead_f->inocache->nlink--;
+                       dead_f->inocache->pino_nlink = 0;
+               } else
+                       dead_f->inocache->pino_nlink--;
                /* NB: Caller must set inode nlink if appropriate */
                mutex_unlock(&dead_f->sem);
        }
index 574cb7532d6c13e8b0fa6b3e1ccc1638ebfc4201..082e844ab2db1fa11ce5a86453f5bdce957df7b2 100644 (file)
@@ -592,7 +592,7 @@ void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache
           When an inode with XATTR is removed, those XATTRs must be removed. */
        struct jffs2_xattr_ref *ref, *_ref;
 
-       if (!ic || ic->nlink > 0)
+       if (!ic || ic->pino_nlink > 0)
                return;
 
        down_write(&c->xattr_sem);
@@ -829,7 +829,7 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
                           ref->xd and ref->ic are not valid yet. */
                        xd = jffs2_find_xattr_datum(c, ref->xid);
                        ic = jffs2_get_ino_cache(c, ref->ino);
-                       if (!xd || !ic || !ic->nlink) {
+                       if (!xd || !ic || !ic->pino_nlink) {
                                dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
                                          ref->ino, ref->xid, ref->xseqno);
                                ref->xseqno |= XREF_DELETE_MARKER;
index 44d9a6a7ec50caad376e36d721a3a42bc5028948..663c069b59b3d6490fd2fa9046d4d0bc3620a581 100644 (file)
 
 #include <linux/capability.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/module.h>
index 7af1f05d59783cf3198771e9ea3945351deb7d7c..a1450086e92f87e64007351ab673bf6274037e70 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -7,6 +7,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/quotaops.h>
 #include <linux/fsnotify.h>
 #include <linux/module.h>
index c135cbdd9127a550d6da103f66fa7cc47584b72e..dca997a93bff32295fd3af13737d17cd24da9d7b 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/signal.h>
 #include <linux/highmem.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/times.h>
 #include <linux/cpuset.h>
 #include <linux/rcupdate.h>
index fcf02f2deeba398f790a4657574cfcbed9b55bc9..808cbdc193d309572c68b03d1b81b318511a4efc 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/init.h>
 #include <linux/capability.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/string.h>
 #include <linux/seq_file.h>
 #include <linux/namei.h>
index 2c292146e2464836983913d7046b3279167f2ce7..8dda969614a9163f602fa62dca53a411c3400136 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/poll.h>
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/rcupdate.h>
 
@@ -298,7 +299,7 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
 #define MAX_SELECT_SECONDS \
        ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
-static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
                           fd_set __user *exp, s64 *timeout)
 {
        fd_set_bits fds;
index 8ead0db359339ca7f5986e3b89ff3b245938557e..619725644c75e4b30d5ba379f9d40a391466efdb 100644 (file)
@@ -207,11 +207,8 @@ static const struct file_operations signalfd_fops = {
 
 asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
 {
-       int error;
        sigset_t sigmask;
        struct signalfd_ctx *ctx;
-       struct file *file;
-       struct inode *inode;
 
        if (sizemask != sizeof(sigset_t) ||
            copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
@@ -230,12 +227,11 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
                 * When we call this, the initialization must be complete, since
                 * anon_inode_getfd() will install the fd.
                 */
-               error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
-                                        &signalfd_fops, ctx);
-               if (error)
-                       goto err_fdalloc;
+               ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx);
+               if (ufd < 0)
+                       kfree(ctx);
        } else {
-               file = fget(ufd);
+               struct file *file = fget(ufd);
                if (!file)
                        return -EBADF;
                ctx = file->private_data;
@@ -252,9 +248,4 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
        }
 
        return ufd;
-
-err_fdalloc:
-       kfree(ctx);
-       return error;
 }
-
index f8b82e73b3bf0ee8a7d9403d6ffdf06ad15f5411..eb53c632f8564a100d92e4670b8c6764776a3514 100644 (file)
@@ -59,6 +59,8 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
        if (error)
                return error;
 
+       iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
+
        error = inode_setattr(inode, iattr);
        if (error)
                return error;
index 5400524e9cb1d2b2e40bf810a1282277e54eec98..d87d354ec42438a4a0794cf964999eb376053c73 100644 (file)
@@ -181,10 +181,8 @@ static struct file *timerfd_fget(int fd)
 
 asmlinkage long sys_timerfd_create(int clockid, int flags)
 {
-       int error, ufd;
+       int ufd;
        struct timerfd_ctx *ctx;
-       struct file *file;
-       struct inode *inode;
 
        if (flags)
                return -EINVAL;
@@ -200,12 +198,9 @@ asmlinkage long sys_timerfd_create(int clockid, int flags)
        ctx->clockid = clockid;
        hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
 
-       error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
-                                &timerfd_fops, ctx);
-       if (error) {
+       ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx);
+       if (ufd < 0)
                kfree(ctx);
-               return error;
-       }
 
        return ufd;
 }
index a2bef77dc9c9878c3f93684acf86548f443d989f..af059d5cb485df8289eda123380f4937c0c7b77c 100644 (file)
@@ -40,9 +40,14 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)
 
 #endif
 
+static bool nsec_special(long nsec)
+{
+       return nsec == UTIME_OMIT || nsec == UTIME_NOW;
+}
+
 static bool nsec_valid(long nsec)
 {
-       if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
+       if (nsec_special(nsec))
                return true;
 
        return nsec >= 0 && nsec <= 999999999;
@@ -119,7 +124,15 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
                        newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
                        newattrs.ia_valid |= ATTR_MTIME_SET;
                }
-       } else {
+       }
+
+       /*
+        * If times is NULL or both times are either UTIME_OMIT or
+        * UTIME_NOW, then need to check permissions, because
+        * inode_change_ok() won't do it.
+        */
+       if (!times || (nsec_special(times[0].tv_nsec) &&
+                      nsec_special(times[1].tv_nsec))) {
                error = -EACCES;
                 if (IS_IMMUTABLE(inode))
                        goto mnt_drop_write_and_out;
index 0b5f881c3d85a252481f30dc713b60a91f5d7c9f..5001390be9582fc1c937aa562671c23cd403f957 100644 (file)
 
 #endif
 
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
 #endif
index 64ccc736f2d87309667fae654b2d472d0ae075d3..839a2fbffa0f34c8c428b6a5793a407749e69ac8 100644 (file)
@@ -9,8 +9,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifndef _ASM_FRV_UNALIGNED_H
-#define _ASM_FRV_UNALIGNED_H
+#ifndef _ASM_UNALIGNED_H
+#define _ASM_UNALIGNED_H
 
 #include <linux/unaligned/le_byteshift.h>
 #include <linux/unaligned/be_byteshift.h>
@@ -19,4 +19,4 @@
 #define get_unaligned  __get_unaligned_be
 #define put_unaligned  __put_unaligned_be
 
-#endif /* _ASM_FRV_UNALIGNED_H */
+#endif /* _ASM_UNALIGNED_H */
index a4a49370793c49ac48a52d52b20691863d4c6483..8f4e3193342e589b8c619e8c2673c3d5544e49a9 100644 (file)
        __rem;                                                  \
  })
 
-static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
-{
-       return dividend / divisor;
-}
-
 #elif BITS_PER_LONG == 32
 
 extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
@@ -54,8 +49,6 @@ extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
        __rem;                                          \
  })
 
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
 #else /* BITS_PER_LONG == ?? */
 
 # error do_div() does not yet support the C64
index e87fa3210a2b837c1692a12d81e1df3296ce0575..fcca30b9f110bead57460586b466912d0eb77d68 100644 (file)
@@ -14,8 +14,8 @@ DECLARE_PER_CPU(struct ia64_cpu, cpu_devices);
 
 DECLARE_PER_CPU(int, cpu_state);
 
-extern int arch_register_cpu(int num);
 #ifdef CONFIG_HOTPLUG_CPU
+extern int arch_register_cpu(int num);
 extern void arch_unregister_cpu(int);
 #endif
 
index f3efaa229525f287dcc4e27a93071c876c770f16..00eb1b130b63fb91cc6594cfa4b2046f4a8cd7d7 100644 (file)
@@ -3,4 +3,9 @@
 
 #include <asm/io.h>
 
+/* Use normal IO mappings for DMI */
+#define dmi_ioremap ioremap
+#define dmi_iounmap(x,l) iounmap(x)
+#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
+
 #endif
index 4ebed77aa4726c5263e0ff1a0ff5dfacc60daf11..260a85ac9d6a6bc4a1784520522e94a686283574 100644 (file)
@@ -423,11 +423,6 @@ extern void __iomem * ioremap(unsigned long offset, unsigned long size);
 extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
 extern void iounmap (volatile void __iomem *addr);
 
-/* Use normal IO mappings for DMI */
-#define dmi_ioremap ioremap
-#define dmi_iounmap(x,l) iounmap(x)
-#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
-
 /*
  * String version of IO memory access ops:
  */
index f30e05583869e8fe3431ac9f0aef20e90e0edc22..2422ac61658a6bb16f465c26acf8c58df1735c6e 100644 (file)
@@ -108,13 +108,11 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
 #define TIF_DB_DISABLED                19      /* debug trap disabled for fsyscall */
 #define TIF_FREEZE             20      /* is freezing for suspend */
 #define TIF_RESTORE_RSE                21      /* user RBS is newer than kernel RBS */
-#define TIF_RESTORE_SIGMASK    22      /* restore signal mask in do_signal() */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
 #define _TIF_SYSCALL_TRACEAUDIT        (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
@@ -131,7 +129,18 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
 #define TIF_WORK_MASK          (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
 
 #define TS_POLLING             1       /* true if in idle loop and not sleeping */
+#define TS_RESTORE_SIGMASK     2       /* restore signal mask in do_signal() */
 
 #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK       1
+static inline void set_restore_sigmask(void)
+{
+       struct thread_info *ti = current_thread_info();
+       ti->status |= TS_RESTORE_SIGMASK;
+       set_bit(TIF_SIGPENDING, &ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
 #endif /* _ASM_IA64_THREAD_INFO_H */
index 33caad1628d4276619daa5b442319a386f4d17a3..8243c931b5c065f4578989361be6f9613b49eb8e 100644 (file)
@@ -25,5 +25,4 @@
        __rem;                                                  \
 })
 
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
 #endif /* _M68K_DIV64_H */
index 3f20419c633aab478da5b587acbc10de2416aaeb..939a0205621712c1416af8036d02ff2a33c2ff12 100644 (file)
@@ -35,7 +35,8 @@
 /*
  * Set number of channels of DMA on ColdFire for different implementations.
  */
-#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
+#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) || \
+       defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
 #define MAX_M68K_DMA_CHANNELS 4
 #elif defined(CONFIG_M5272)
 #define MAX_M68K_DMA_CHANNELS 1
index 96c45101832491ecbb7e0cabdb5b49d49f5fa5d2..6044397adb64f89d8923cec107ddfd5c5d04bdf2 100644 (file)
@@ -1,13 +1,16 @@
 #ifndef _M68KNOMMU_PARAM_H
 #define _M68KNOMMU_PARAM_H
 
-#define HZ CONFIG_HZ
-
 #ifdef __KERNEL__
+#define HZ CONFIG_HZ
 #define        USER_HZ         HZ
 #define        CLOCKS_PER_SEC  (USER_HZ)
 #endif
 
+#ifndef HZ
+#define HZ     100
+#endif
+
 #define EXEC_PAGESIZE  4096
 
 #ifndef NOGROUP
index 716371bd098076c7297e5ef90a2400d42387c620..d1d699105c1106b724340104786f95ce8df39188 100644 (file)
@@ -82,7 +82,6 @@
        (n) = __quot; \
        __mod; })
 
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
 #endif /* (_MIPS_SZLONG == 32) */
 
 #if (_MIPS_SZLONG == 64)
@@ -106,11 +105,6 @@ extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
        (n) = __quot; \
        __mod; })
 
-static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
-{
-       return dividend / divisor;
-}
-
 #endif /* (_MIPS_SZLONG == 64) */
 
 #endif /* _ASM_DIV64_H */
index bf9c515a998c8e0bc613952229f41ebe967fd4c4..3a8329b3e8694493c6b018eea7820873d04110f8 100644 (file)
@@ -97,7 +97,4 @@ signed __muldiv64s(signed val, signed mult, signed div)
        return result;
 }
 
-extern __attribute__((const))
-uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
 #endif /* _ASM_DIV64 */
index 7b73b2cd5b340be8212d45657eb44ad9cda71425..1e17f7409cabc072df18f3f516b0df0bc2a58506 100644 (file)
@@ -3,5 +3,4 @@
 
 #include "asm/arch/div64.h"
 
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
 #endif
index 0dbf8bf3ef0a8d06308ea3cf8e72612c28c016c2..9a2d644c08efc0981dbc13b1700e81917fef7c63 100644 (file)
        __mod;                                                  \
 })
 
-/*
- * (long)X = ((long long)divs) / (long)div
- * (long)rem = ((long long)divs) % (long)div
- *
- * Warning, this will do an exception if X overflows.
- */
-#define div_long_long_rem(a, b, c) div_ll_X_l_rem(a, b, c)
-
-static inline long div_ll_X_l_rem(long long divs, long div, long *rem)
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
 {
-       long dum2;
-       asm("divl %2":"=a"(dum2), "=d"(*rem)
-           : "rm"(div), "A"(divs));
-
-       return dum2;
-
+       union {
+               u64 v64;
+               u32 v32[2];
+       } d = { dividend };
+       u32 upper;
+
+       upper = d.v32[1];
+       d.v32[1] = 0;
+       if (upper >= divisor) {
+               d.v32[1] = upper / divisor;
+               upper %= divisor;
+       }
+       asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
+               "rm" (divisor), "0" (d.v32[0]), "1" (upper));
+       return d.v64;
 }
-
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
+#define div_u64_rem    div_u64_rem
 
 #else
 # include <asm-generic/div64.h>
index 1241e6ad1935b99c6273554eb8501f05833b28cb..4edf7514a75033d8173428e1ce1640995a87f154 100644 (file)
@@ -27,6 +27,7 @@ static inline void *dmi_alloc(unsigned len)
 
 #endif
 
+/* Use early IO mappings for DMI because it's initialized early */
 #define dmi_ioremap early_ioremap
 #define dmi_iounmap early_iounmap
 
index 6e73467a4fb13783ba21a73108e238e8e4e35fe7..049e81e797a0919e8090135c5b16fe5b99a32c5e 100644 (file)
@@ -133,11 +133,6 @@ extern void *early_ioremap(unsigned long offset, unsigned long size);
 extern void early_iounmap(void *addr, unsigned long size);
 extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
 
-/* Use early IO mappings for DMI because it's initialized early */
-#define dmi_ioremap early_ioremap
-#define dmi_iounmap early_iounmap
-#define dmi_alloc alloc_bootmem
-
 /*
  * ISA I/O bus memory addresses are 1:1 with the physical address.
  */
index 0a6634f62abe2c1c37d91d078846cdeef51f15c3..21003b56ae959e0db51ebd1ac689ccb83ecbda37 100644 (file)
@@ -109,13 +109,8 @@ static inline int cpu_to_logical_apicid(int cpu)
 
 static inline int cpu_present_to_apicid(int mps_cpu)
 {
-#ifdef CONFIG_X86_64
-       if (cpu_present(mps_cpu))
+       if (mps_cpu < NR_CPUS && cpu_present(mps_cpu))
                return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
-#else
-       if (mps_cpu < get_physical_broadcast())
-               return  mps_cpu;
-#endif
        else
                return BAD_APICID;
 }
index 2e7974ec77eca6e94b2ee503d02580a87db717a2..559105220a477e2be9cfbd87eee62d1cd68767c2 100644 (file)
@@ -3,9 +3,6 @@
 
 #include <asm/processor-flags.h>
 
-/* migration helper, for KVM - will be removed in 2.6.25: */
-#define Xgt_desc_struct        desc_ptr
-
 /* Forward declaration, a strange C thing */
 struct task_struct;
 struct mm_struct;
index 1e17bcce450e0ffcb47dbea2939c7366f769f29f..6c8b41b03f6def5593696d12752c3627028e10b3 100644 (file)
@@ -20,7 +20,11 @@ extern void syscall32_cpu_init(void);
 
 extern void check_efer(void);
 
+#ifdef CONFIG_X86_BIOS_REBOOT
 extern int reboot_force;
+#else
+static const int reboot_force = 0;
+#endif
 
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
 
index 224658b8d80689560e6ebf7c7bd94c41a2ea76bf..833d208c25d64194525e8b1ff09d8ddaf261251d 100644 (file)
@@ -57,10 +57,14 @@ static inline void scatterwalk_sg_chain(struct scatterlist *sg1, int num,
                                        struct scatterlist *sg2)
 {
        sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0);
+       sg1[num - 1].page_link &= ~0x02;
 }
 
 static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
 {
+       if (sg_is_last(sg))
+               return NULL;
+
        return (++sg)->length ? sg : (void *)sg_page(sg);
 }
 
index 78fade0a1e3528aaae16a306a47f22e91336e0e7..b7d81b2a90411bb16b5b4de8a7766c8547e1d01f 100644 (file)
@@ -346,6 +346,11 @@ unifdef-y += videodev.h
 unifdef-y += virtio_config.h
 unifdef-y += virtio_blk.h
 unifdef-y += virtio_net.h
+unifdef-y += virtio_9p.h
+unifdef-y += virtio_balloon.h
+unifdef-y += virtio_console.h
+unifdef-y += virtio_pci.h
+unifdef-y += virtio_ring.h
 unifdef-y += vt.h
 unifdef-y += wait.h
 unifdef-y += wanrouter.h
index b2e1ba325b9a4c0d044ea20c6629bda8d4d27200..6129e58ca7c99407716acbf6482e2d02d09956e9 100644 (file)
@@ -8,8 +8,7 @@
 #ifndef _LINUX_ANON_INODES_H
 #define _LINUX_ANON_INODES_H
 
-int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
-                    const char *name, const struct file_operations *fops,
+int anon_inode_getfd(const char *name, const struct file_operations *fops,
                     void *priv);
 
 #endif /* _LINUX_ANON_INODES_H */
diff --git a/include/linux/calc64.h b/include/linux/calc64.h
deleted file mode 100644 (file)
index ebf4b8f..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _LINUX_CALC64_H
-#define _LINUX_CALC64_H
-
-#include <linux/types.h>
-#include <asm/div64.h>
-
-/*
- * This is a generic macro which is used when the architecture
- * specific div64.h does not provide a optimized one.
- *
- * The 64bit dividend is divided by the divisor (data type long), the
- * result is returned and the remainder stored in the variable
- * referenced by remainder (data type long *). In contrast to the
- * do_div macro the dividend is kept intact.
- */
-#ifndef div_long_long_rem
-#define div_long_long_rem(dividend, divisor, remainder)        \
-       do_div_llr((dividend), divisor, remainder)
-
-static inline unsigned long do_div_llr(const long long dividend,
-                                      const long divisor, long *remainder)
-{
-       u64 result = dividend;
-
-       *(remainder) = do_div(result, divisor);
-       return (unsigned long) result;
-}
-#endif
-
-/*
- * Sign aware variation of the above. On some architectures a
- * negative dividend leads to an divide overflow exception, which
- * is avoided by the sign check.
- */
-static inline long div_long_long_rem_signed(const long long dividend,
-                                           const long divisor, long *remainder)
-{
-       long res;
-
-       if (unlikely(dividend < 0)) {
-               res = -div_long_long_rem(-dividend, divisor, remainder);
-               *remainder = -(*remainder);
-       } else
-               res = div_long_long_rem(dividend, divisor, remainder);
-
-       return res;
-}
-
-#endif
index 35094479ca557012e043ea0def0fbf9b6df11e65..55e434feec993d9656ccf6bcd31964005daa9667 100644 (file)
@@ -93,6 +93,8 @@ struct clocksource {
 #endif
 };
 
+extern struct clocksource *clock;      /* current clocksource */
+
 /*
  * Clock source flags bits::
  */
index 8fa7857e153bc7f7649ea25e088924fb0a6190f9..cf8d11cad5aef24dd99c57c3f7406d9ea4c541d6 100644 (file)
@@ -65,10 +65,11 @@ struct compat_timex {
        compat_long_t calcnt;
        compat_long_t errcnt;
        compat_long_t stbcnt;
+       compat_int_t tai;
 
        compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
        compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
-       compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
+       compat_int_t :32; compat_int_t :32; compat_int_t :32;
 };
 
 #define _COMPAT_NSIG_WORDS     (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
index 1a060265aceae6f31b2875d86f660dc9baaee1ab..8c23e3dfe3ac215c721c1e54942f8260b25f3d43 100644 (file)
@@ -35,7 +35,6 @@ struct device;
 struct device_driver;
 struct driver_private;
 struct class;
-struct class_device;
 struct bus_type;
 struct bus_type_private;
 
@@ -190,13 +189,10 @@ struct class {
        struct kset             class_dirs;
        struct semaphore        sem; /* locks children, devices, interfaces */
        struct class_attribute          *class_attrs;
-       struct class_device_attribute   *class_dev_attrs;
        struct device_attribute         *dev_attrs;
 
-       int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
        int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
 
-       void (*release)(struct class_device *dev);
        void (*class_release)(struct class *class);
        void (*dev_release)(struct device *dev);
 
@@ -210,9 +206,6 @@ extern int class_for_each_device(struct class *class, void *data,
                                 int (*fn)(struct device *dev, void *data));
 extern struct device *class_find_device(struct class *class, void *data,
                                        int (*match)(struct device *, void *));
-extern struct class_device *class_find_child(struct class *class, void *data,
-                                  int (*match)(struct class_device *, void *));
-
 
 struct class_attribute {
        struct attribute attr;
@@ -228,92 +221,10 @@ extern int __must_check class_create_file(struct class *class,
 extern void class_remove_file(struct class *class,
                              const struct class_attribute *attr);
 
-struct class_device_attribute {
-       struct attribute attr;
-       ssize_t (*show)(struct class_device *, char *buf);
-       ssize_t (*store)(struct class_device *, const char *buf, size_t count);
-};
-
-#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store)         \
-struct class_device_attribute class_device_attr_##_name =      \
-       __ATTR(_name, _mode, _show, _store)
-
-extern int __must_check class_device_create_file(struct class_device *,
-                                   const struct class_device_attribute *);
-
-/**
- * struct class_device - class devices
- * @class: pointer to the parent class for this class device.  This is required.
- * @devt: for internal use by the driver core only.
- * @node: for internal use by the driver core only.
- * @kobj: for internal use by the driver core only.
- * @groups: optional additional groups to be created
- * @dev: if set, a symlink to the struct device is created in the sysfs
- * directory for this struct class device.
- * @class_data: pointer to whatever you want to store here for this struct
- * class_device.  Use class_get_devdata() and class_set_devdata() to get and
- * set this pointer.
- * @parent: pointer to a struct class_device that is the parent of this struct
- * class_device.  If NULL, this class_device will show up at the root of the
- * struct class in sysfs (which is probably what you want to have happen.)
- * @release: pointer to a release function for this struct class_device.  If
- * set, this will be called instead of the class specific release function.
- * Only use this if you want to override the default release function, like
- * when you are nesting class_device structures.
- * @uevent: pointer to a uevent function for this struct class_device.  If
- * set, this will be called instead of the class specific uevent function.
- * Only use this if you want to override the default uevent function, like
- * when you are nesting class_device structures.
- */
-struct class_device {
-       struct list_head        node;
-
-       struct kobject          kobj;
-       struct class            *class;
-       dev_t                   devt;
-       struct device           *dev;
-       void                    *class_data;
-       struct class_device     *parent;
-       struct attribute_group  **groups;
-
-       void (*release)(struct class_device *dev);
-       int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
-       char class_id[BUS_ID_SIZE];
-};
-
-static inline void *class_get_devdata(struct class_device *dev)
-{
-       return dev->class_data;
-}
-
-static inline void class_set_devdata(struct class_device *dev, void *data)
-{
-       dev->class_data = data;
-}
-
-
-extern int __must_check class_device_register(struct class_device *);
-extern void class_device_unregister(struct class_device *);
-extern void class_device_initialize(struct class_device *);
-extern int __must_check class_device_add(struct class_device *);
-extern void class_device_del(struct class_device *);
-
-extern struct class_device *class_device_get(struct class_device *);
-extern void class_device_put(struct class_device *);
-
-extern void class_device_remove_file(struct class_device *,
-                                    const struct class_device_attribute *);
-extern int __must_check class_device_create_bin_file(struct class_device *,
-                                       struct bin_attribute *);
-extern void class_device_remove_bin_file(struct class_device *,
-                                        struct bin_attribute *);
-
 struct class_interface {
        struct list_head        node;
        struct class            *class;
 
-       int (*add)      (struct class_device *, struct class_interface *);
-       void (*remove)  (struct class_device *, struct class_interface *);
        int (*add_dev)          (struct device *, struct class_interface *);
        void (*remove_dev)      (struct device *, struct class_interface *);
 };
@@ -323,13 +234,6 @@ extern void class_interface_unregister(struct class_interface *);
 
 extern struct class *class_create(struct module *owner, const char *name);
 extern void class_destroy(struct class *cls);
-extern struct class_device *class_device_create(struct class *cls,
-                                               struct class_device *parent,
-                                               dev_t devt,
-                                               struct device *device,
-                                               const char *fmt, ...)
-                                       __attribute__((format(printf, 5, 6)));
-extern void class_device_destroy(struct class *cls, dev_t devt);
 
 /*
  * The type of device, "struct device" is embedded in. A class
@@ -465,7 +369,6 @@ struct device {
        spinlock_t              devres_lock;
        struct list_head        devres_head;
 
-       /* class_device migration path */
        struct list_head        node;
        struct class            *class;
        dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
@@ -477,6 +380,12 @@ struct device {
 /* Get the wakeup routines, which depend on struct device */
 #include <linux/pm_wakeup.h>
 
+static inline const char *dev_name(struct device *dev)
+{
+       /* will be changed into kobject_name(&dev->kobj) in the near future */
+       return dev->bus_id;
+}
+
 #ifdef CONFIG_NUMA
 static inline int dev_to_node(struct device *dev)
 {
@@ -575,7 +484,7 @@ extern void sysdev_shutdown(void);
 extern const char *dev_driver_string(struct device *dev);
 #define dev_printk(level, dev, format, arg...) \
        printk(level "%s %s: " format , dev_driver_string(dev) , \
-              (dev)->bus_id , ## arg)
+              dev_name(dev) , ## arg)
 
 #define dev_emerg(dev, format, arg...)         \
        dev_printk(KERN_EMERG , dev , format , ## arg)
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
new file mode 100644 (file)
index 0000000..a118f3c
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * descriptor table internals; you almost certainly want file.h instead.
+ */
+
+#ifndef __LINUX_FDTABLE_H
+#define __LINUX_FDTABLE_H
+
+#include <asm/atomic.h>
+#include <linux/posix_types.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/types.h>
+
+/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
+ * The embedded_fd_set is a small fd_set,
+ * suitable for most tasks (which open <= BITS_PER_LONG files)
+ */
+struct embedded_fd_set {
+       unsigned long fds_bits[1];
+};
+
+struct fdtable {
+       unsigned int max_fds;
+       struct file ** fd;      /* current fd array */
+       fd_set *close_on_exec;
+       fd_set *open_fds;
+       struct rcu_head rcu;
+       struct fdtable *next;
+};
+
+/*
+ * Open file table structure
+ */
+struct files_struct {
+  /*
+   * read mostly part
+   */
+       atomic_t count;
+       struct fdtable *fdt;
+       struct fdtable fdtab;
+  /*
+   * written part on a separate cache line in SMP
+   */
+       spinlock_t file_lock ____cacheline_aligned_in_smp;
+       int next_fd;
+       struct embedded_fd_set close_on_exec_init;
+       struct embedded_fd_set open_fds_init;
+       struct file * fd_array[NR_OPEN_DEFAULT];
+};
+
+#define files_fdtable(files) (rcu_dereference((files)->fdt))
+
+extern struct kmem_cache *filp_cachep;
+
+struct file_operations;
+struct vfsmount;
+struct dentry;
+
+extern int expand_files(struct files_struct *, int nr);
+extern void free_fdtable_rcu(struct rcu_head *rcu);
+extern void __init files_defer_init(void);
+
+static inline void free_fdtable(struct fdtable *fdt)
+{
+       call_rcu(&fdt->rcu, free_fdtable_rcu);
+}
+
+static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
+{
+       struct file * file = NULL;
+       struct fdtable *fdt = files_fdtable(files);
+
+       if (fd < fdt->max_fds)
+               file = rcu_dereference(fdt->fd[fd]);
+       return file;
+}
+
+/*
+ * Check whether the specified fd has an open file.
+ */
+#define fcheck(fd)     fcheck_files(current->files, fd)
+
+struct task_struct;
+
+struct files_struct *get_files_struct(struct task_struct *);
+void put_files_struct(struct files_struct *fs);
+void reset_files_struct(struct files_struct *);
+int unshare_files(struct files_struct **);
+
+extern struct kmem_cache *files_cachep;
+
+#endif /* __LINUX_FDTABLE_H */
index 69baf5a4f0a582cfeb061af5735e4a2d70e701e6..27c64bdc68c961baa821614bbfc6246951393acd 100644 (file)
@@ -5,59 +5,11 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
-#include <asm/atomic.h>
-#include <linux/posix_types.h>
 #include <linux/compiler.h>
-#include <linux/spinlock.h>
-#include <linux/rcupdate.h>
 #include <linux/types.h>
+#include <linux/posix_types.h>
 
-/*
- * The default fd array needs to be at least BITS_PER_LONG,
- * as this is the granularity returned by copy_fdset().
- */
-#define NR_OPEN_DEFAULT BITS_PER_LONG
-
-/*
- * The embedded_fd_set is a small fd_set,
- * suitable for most tasks (which open <= BITS_PER_LONG files)
- */
-struct embedded_fd_set {
-       unsigned long fds_bits[1];
-};
-
-struct fdtable {
-       unsigned int max_fds;
-       struct file ** fd;      /* current fd array */
-       fd_set *close_on_exec;
-       fd_set *open_fds;
-       struct rcu_head rcu;
-       struct fdtable *next;
-};
-
-/*
- * Open file table structure
- */
-struct files_struct {
-  /*
-   * read mostly part
-   */
-       atomic_t count;
-       struct fdtable *fdt;
-       struct fdtable fdtab;
-  /*
-   * written part on a separate cache line in SMP
-   */
-       spinlock_t file_lock ____cacheline_aligned_in_smp;
-       int next_fd;
-       struct embedded_fd_set close_on_exec_init;
-       struct embedded_fd_set open_fds_init;
-       struct file * fd_array[NR_OPEN_DEFAULT];
-};
-
-#define files_fdtable(files) (rcu_dereference((files)->fdt))
-
-extern struct kmem_cache *filp_cachep;
+struct file;
 
 extern void __fput(struct file *);
 extern void fput(struct file *);
@@ -85,41 +37,7 @@ extern void put_filp(struct file *);
 extern int get_unused_fd(void);
 extern int get_unused_fd_flags(int flags);
 extern void put_unused_fd(unsigned int fd);
-struct kmem_cache;
-
-extern int expand_files(struct files_struct *, int nr);
-extern void free_fdtable_rcu(struct rcu_head *rcu);
-extern void __init files_defer_init(void);
-
-static inline void free_fdtable(struct fdtable *fdt)
-{
-       call_rcu(&fdt->rcu, free_fdtable_rcu);
-}
-
-static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
-{
-       struct file * file = NULL;
-       struct fdtable *fdt = files_fdtable(files);
-
-       if (fd < fdt->max_fds)
-               file = rcu_dereference(fdt->fd[fd]);
-       return file;
-}
-
-/*
- * Check whether the specified fd has an open file.
- */
-#define fcheck(fd)     fcheck_files(current->files, fd)
 
 extern void fd_install(unsigned int fd, struct file *file);
 
-struct task_struct;
-
-struct files_struct *get_files_struct(struct task_struct *);
-void put_files_struct(struct files_struct *fs);
-void reset_files_struct(struct files_struct *);
-int unshare_files(struct files_struct **);
-
-extern struct kmem_cache *files_cachep;
-
 #endif /* __LINUX_FILE_H */
index bf6b8a61f8db22913e5b9a09fa915adb6e69c768..b24c2875aa0570524502e12c97d8e7c3b0d44fa0 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _LINUX__INIT_TASK_H
 #define _LINUX__INIT_TASK_H
 
-#include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/rcupdate.h>
 #include <linux/irqflags.h>
 #include <linux/utsname.h>
index e3b2dda6c8eb5dd97c3ec78befe9c5c0cdb735a0..3a03a3604cce7e61e024c793739d227b5933176f 100644 (file)
@@ -58,9 +58,9 @@ static inline void devm_ioport_unmap(struct device *dev, void __iomem *addr)
 }
 #endif
 
-void __iomem * devm_ioremap(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
                            unsigned long size);
-void __iomem * devm_ioremap_nocache(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
                                    unsigned long size);
 void devm_iounmap(struct device *dev, void __iomem *addr);
 int check_signature(const volatile void __iomem *io_addr,
index 1883a85625dd6a7d0290e6add5a3ea6bd9936fd9..552e0ec269c9640b0536e2306a07236b9e0d43f8 100644 (file)
@@ -61,6 +61,7 @@ typedef       void (*irq_flow_handler_t)(unsigned int irq,
 #define IRQ_WAKEUP             0x00100000      /* IRQ triggers system wakeup */
 #define IRQ_MOVE_PENDING       0x00200000      /* need to re-target IRQ destination */
 #define IRQ_NO_BALANCING       0x00400000      /* IRQ is excluded from balancing */
+#define IRQ_SPURIOUS_DISABLED  0x00800000      /* IRQ was disabled by the spurious trap */
 
 #ifdef CONFIG_IRQ_PER_CPU
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
index 33ef710dac24481774d14d2333f73e0af34de6a5..abb6ac639e8e19740c8bbd30148db72a1028d031 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _LINUX_JIFFIES_H
 #define _LINUX_JIFFIES_H
 
-#include <linux/calc64.h>
+#include <linux/math64.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/time.h>
index 74071254c9d38c348b0bba649d9e8c9ebb4cb049..06c338ef7f1b9ee62cc43fa4e30e9d79a3acc072 100644 (file)
@@ -25,37 +25,47 @@ struct klist {
        void                    (*put)(struct klist_node *);
 };
 
+#define KLIST_INIT(_name, _get, _put)                                  \
+       { .k_lock       = __SPIN_LOCK_UNLOCKED(_name.k_lock),           \
+         .k_list       = LIST_HEAD_INIT(_name.k_list),                 \
+         .get          = _get,                                         \
+         .put          = _put, }
 
-extern void klist_init(struct klist * k, void (*get)(struct klist_node *),
+#define DEFINE_KLIST(_name, _get, _put)                                        \
+       struct klist _name = KLIST_INIT(_name, _get, _put)
+
+extern void klist_init(struct klist *k, void (*get)(struct klist_node *),
                       void (*put)(struct klist_node *));
 
 struct klist_node {
-       struct klist            * n_klist;
+       struct klist            *n_klist;
        struct list_head        n_node;
        struct kref             n_ref;
        struct completion       n_removed;
 };
 
-extern void klist_add_tail(struct klist_node * n, struct klist * k);
-extern void klist_add_head(struct klist_node * n, struct klist * k);
+extern void klist_add_tail(struct klist_node *n, struct klist *k);
+extern void klist_add_head(struct klist_node *n, struct klist *k);
+extern void klist_add_after(struct klist_node *n, struct klist_node *pos);
+extern void klist_add_before(struct klist_node *n, struct klist_node *pos);
 
-extern void klist_del(struct klist_node * n);
-extern void klist_remove(struct klist_node * n);
+extern void klist_del(struct klist_node *n);
+extern void klist_remove(struct klist_node *n);
 
-extern int klist_node_attached(struct klist_node * n);
+extern int klist_node_attached(struct klist_node *n);
 
 
 struct klist_iter {
-       struct klist            * i_klist;
-       struct list_head        * i_head;
-       struct klist_node       * i_cur;
+       struct klist            *i_klist;
+       struct list_head        *i_head;
+       struct klist_node       *i_cur;
 };
 
 
-extern void klist_iter_init(struct klist * k, struct klist_iter * i);
-extern void klist_iter_init_node(struct klist * k, struct klist_iter * i, 
-                                struct klist_node * n);
-extern void klist_iter_exit(struct klist_iter * i);
-extern struct klist_node * klist_next(struct klist_iter * i);
+extern void klist_iter_init(struct klist *k, struct klist_iter *i);
+extern void klist_iter_init_node(struct klist *k, struct klist_iter *i,
+                                struct klist_node *n);
+extern void klist_iter_exit(struct klist_iter *i);
+extern struct klist_node *klist_next(struct klist_iter *i);
 
 #endif
diff --git a/include/linux/math64.h b/include/linux/math64.h
new file mode 100644 (file)
index 0000000..c1a5f81
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef _LINUX_MATH64_H
+#define _LINUX_MATH64_H
+
+#include <linux/types.h>
+#include <asm/div64.h>
+
+#if BITS_PER_LONG == 64
+
+/**
+ * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
+ *
+ * This is commonly provided by 32bit archs to provide an optimized 64bit
+ * divide.
+ */
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+       *remainder = dividend % divisor;
+       return dividend / divisor;
+}
+
+/**
+ * div_s64_rem - signed 64bit divide with 32bit divisor with remainder
+ */
+static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+       *remainder = dividend % divisor;
+       return dividend / divisor;
+}
+
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ */
+static inline u64 div64_u64(u64 dividend, u64 divisor)
+{
+       return dividend / divisor;
+}
+
+#elif BITS_PER_LONG == 32
+
+#ifndef div_u64_rem
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+       *remainder = do_div(dividend, divisor);
+       return dividend;
+}
+#endif
+
+#ifndef div_s64_rem
+extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
+#endif
+
+#ifndef div64_u64
+extern u64 div64_u64(u64 dividend, u64 divisor);
+#endif
+
+#endif /* BITS_PER_LONG */
+
+/**
+ * div_u64 - unsigned 64bit divide with 32bit divisor
+ *
+ * This is the most common 64bit divide and should be used if possible,
+ * as many 32bit archs can optimize this variant better than a full 64bit
+ * divide.
+ */
+#ifndef div_u64
+static inline u64 div_u64(u64 dividend, u32 divisor)
+{
+       u32 remainder;
+       return div_u64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+/**
+ * div_s64 - signed 64bit divide with 32bit divisor
+ */
+#ifndef div_s64
+static inline s64 div_s64(s64 dividend, s32 divisor)
+{
+       s32 remainder;
+       return div_s64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+#endif /* _LINUX_MATH64_H */
index 819c4e889bf16f0157f45ad4326afa7e83418582..3e03b1acbc94a8ba7fbbd28e394f442c4710f2f9 100644 (file)
@@ -190,7 +190,7 @@ void *__symbol_get_gpl(const char *symbol);
        extern typeof(sym) sym;                                 \
        __CRC_SYMBOL(sym, sec)                                  \
        static const char __kstrtab_##sym[]                     \
-       __attribute__((section("__ksymtab_strings")))           \
+       __attribute__((section("__ksymtab_strings"), aligned(1))) \
        = MODULE_SYMBOL_PREFIX #sym;                            \
        static const struct kernel_symbol __ksymtab_##sym       \
        __used                                                  \
@@ -229,23 +229,6 @@ enum module_state
        MODULE_STATE_GOING,
 };
 
-/* Similar stuff for section attributes. */
-struct module_sect_attr
-{
-       struct module_attribute mattr;
-       char *name;
-       unsigned long address;
-};
-
-struct module_sect_attrs
-{
-       struct attribute_group grp;
-       int nsections;
-       struct module_sect_attr attrs[0];
-};
-
-struct module_param_attrs;
-
 struct module
 {
        enum module_state state;
diff --git a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h
deleted file mode 100644 (file)
index 9006feb..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $
- */
-
-#ifndef __LINUX_MTD_JEDEC_H__
-#define __LINUX_MTD_JEDEC_H__
-
-#include <linux/types.h>
-
-#define MAX_JEDEC_CHIPS 16
-
-// Listing of all supported chips and their information
-struct JEDECTable
-{
-   __u16 jedec;
-   char *name;
-   unsigned long size;
-   unsigned long sectorsize;
-   __u32 capabilities;
-};
-
-// JEDEC being 0 is the end of the chip array
-struct jedec_flash_chip
-{
-   __u16 jedec;
-   unsigned long size;
-   unsigned long sectorsize;
-
-   // *(__u8*)(base + (adder << addrshift)) = data << datashift
-   // Address size = size << addrshift
-   unsigned long base;           // Byte 0 of the flash, will be unaligned
-   unsigned int datashift;       // Useful for 32bit/16bit accesses
-   unsigned int addrshift;
-   unsigned long offset;         // linerized start. base==offset for unbanked, uninterleaved flash
-
-   __u32 capabilities;
-
-   // These markers are filled in by the flash_chip_scan function
-   unsigned long start;
-   unsigned long length;
-};
-
-struct jedec_private
-{
-   unsigned long size;         // Total size of all the devices
-
-   /* Bank handling. If sum(bank_fill) == size then this is linear flash.
-      Otherwise the mapping has holes in it. bank_fill may be used to
-      find the holes, but in the common symetric case
-      bank_fill[0] == bank_fill[*], thus addresses may be computed
-      mathmatically. bank_fill must be powers of two */
-   unsigned is_banked;
-   unsigned long bank_fill[MAX_JEDEC_CHIPS];
-
-   struct jedec_flash_chip chips[MAX_JEDEC_CHIPS];
-};
-
-#endif
index 0a13bb35f044fa249c58f54e0ceab9bbe9e01f23..245f9098e171cfe2bf5b27860f6be2e0365fa57f 100644 (file)
@@ -143,10 +143,12 @@ struct mtd_info {
        int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
 
        /* This stuff for eXecute-In-Place */
-       int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
+       /* phys is optional and may be set to NULL */
+       int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
+                       size_t *retlen, void **virt, resource_size_t *phys);
 
        /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
-       void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
+       void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
 
 
        int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
index a7f6d20ad407bf7dcbb5859ed6dc78a6a2cfc7d7..5cc070c24d88646229bfd7f1f64aa06b76ebdbac 100644 (file)
@@ -36,8 +36,9 @@ struct mypriv {
  * Function Prototypes
  */
 static int pmc551_erase(struct mtd_info *, struct erase_info *);
-static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
-static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
+static void pmc551_unpoint(struct mtd_info *, loff_t, size_t);
+static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, void **virt, resource_size_t *phys);
 static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
index e5a53daf17f14c88705c2aa7a752e515a0b23dcd..cf6dbd759395fbb4a9680e52f0dd960bbbac6605 100644 (file)
 #define PCI_DEVICE_ID_NEO_2DB9PRI       0x00C9
 #define PCI_DEVICE_ID_NEO_2RJ45         0x00CA
 #define PCI_DEVICE_ID_NEO_2RJ45PRI      0x00CB
+#define PCIE_DEVICE_ID_NEO_4_IBM        0x00F4
 
 #define PCI_VENDOR_ID_XIRCOM           0x115d
 #define PCI_DEVICE_ID_XIRCOM_RBM56G    0x0101
index 16d813b364ef41c26d5404a53c480e3b0dbef0d3..ef453828877a35aefc4bbdd1a4753734bbccd882 100644 (file)
@@ -117,6 +117,8 @@ void zero_fd_set(unsigned long nr, unsigned long *fdset)
 extern int do_select(int n, fd_set_bits *fds, s64 *timeout);
 extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds,
                       s64 *timeout);
+extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+                          fd_set __user *exp, s64 *timeout);
 
 #endif /* KERNEL */
 
index 52e49dce658402fc652c082ff1e6979ff6ead7e2..dcddfb2009479f42a543363d0c0873c76d4bfcee 100644 (file)
@@ -347,6 +347,9 @@ struct quota_info {
        ((type) == USRQUOTA ? (sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED) : \
                              (sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED))
 
+#define sb_any_quota_suspended(sb) (sb_has_quota_suspended(sb, USRQUOTA) | \
+                                 sb_has_quota_suspended(sb, GRPQUOTA))
+
 int register_quota_format(struct quota_format_type *fmt);
 void unregister_quota_format(struct quota_format_type *fmt);
 
index c5d3fcad7b57c87449d7de9085daa64cd80f984f..efdc44593b522054dda0454f105fb0636b8ec0c2 100644 (file)
@@ -109,5 +109,7 @@ extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
 
+extern bool sysfs_streq(const char *s1, const char *s2);
+
 #endif
 #endif /* _LINUX_STRING_H_ */
index add3c5a40827f7824169159a140884da38291d17..27bad59dae7946b7a5386cd5e5daeb2fe3ee5c4e 100644 (file)
@@ -190,6 +190,18 @@ static inline int sysfs_create_group(struct kobject *kobj,
        return 0;
 }
 
+static inline int sysfs_update_group(struct kobject *kobj,
+                               const struct attribute_group *grp)
+{
+       return 0;
+}
+
+static inline int sysfs_update_group(struct kobject *kobj,
+                               const struct attribute_group *grp)
+{
+       return 0;
+}
+
 static inline void sysfs_remove_group(struct kobject *kobj,
                                      const struct attribute_group *grp)
 {
index 8ea3e71ba7fa8ff17d8de5587f482450c349ef36..fc6035d29d568a018e5c43f6575e5b860379fa96 100644 (file)
@@ -58,6 +58,8 @@
 
 #include <asm/param.h>
 
+#define NTP_API                4       /* NTP API version */
+
 /*
  * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
  * for a slightly underdamped convergence characteristic. SHIFT_KH
 #define MAXTC          10      /* maximum time constant (shift) */
 
 /*
- * The SHIFT_UPDATE define establishes the decimal point of the
- * time_offset variable which represents the current offset with
- * respect to standard time.
- *
  * SHIFT_USEC defines the scaling (shift) of the time_freq and
  * time_tolerance variables, which represent the current frequency
  * offset and maximum frequency tolerance.
  */
-#define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */
 #define SHIFT_USEC 16          /* frequency offset scale (shift) */
-#define SHIFT_NSEC 12          /* kernel frequency offset scale */
-
-#define MAXPHASE 512000L        /* max phase error (us) */
-#define MAXFREQ (512L << SHIFT_USEC)  /* max frequency error (ppm) */
-#define MAXFREQ_NSEC (512000L << SHIFT_NSEC) /* max frequency error (ppb) */
+#define PPM_SCALE (NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC))
+#define PPM_SCALE_INV_SHIFT 20
+#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \
+                      PPM_SCALE + 1)
+
+#define MAXPHASE 500000000l    /* max phase error (ns) */
+#define MAXFREQ 500000         /* max frequency error (ns/s) */
+#define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT)
 #define MINSEC 256             /* min interval between updates (s) */
 #define MAXSEC 2048            /* max interval between updates (s) */
-#define        NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */
+#define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */
 
 /*
  * syscall interface - used (mainly by NTP daemon)
@@ -121,9 +121,11 @@ struct timex {
        long errcnt;            /* calibration errors (ro) */
        long stbcnt;            /* stability limit exceeded (ro) */
 
+       int tai;                /* TAI offset (ro) */
+
        int  :32; int  :32; int  :32; int  :32;
        int  :32; int  :32; int  :32; int  :32;
-       int  :32; int  :32; int  :32; int  :32;
+       int  :32; int  :32; int  :32;
 };
 
 /*
@@ -135,6 +137,9 @@ struct timex {
 #define ADJ_ESTERROR           0x0008  /* estimated time error */
 #define ADJ_STATUS             0x0010  /* clock status */
 #define ADJ_TIMECONST          0x0020  /* pll time constant */
+#define ADJ_TAI                        0x0080  /* set TAI offset */
+#define ADJ_MICRO              0x1000  /* select microsecond resolution */
+#define ADJ_NANO               0x2000  /* select nanosecond resolution */
 #define ADJ_TICK               0x4000  /* tick value */
 #define ADJ_OFFSET_SINGLESHOT  0x8001  /* old-fashioned adjtime */
 #define ADJ_OFFSET_SS_READ     0xa001  /* read-only adjtime */
@@ -146,8 +151,6 @@ struct timex {
 #define MOD_ESTERROR   ADJ_ESTERROR
 #define MOD_STATUS     ADJ_STATUS
 #define MOD_TIMECONST  ADJ_TIMECONST
-#define MOD_CLKB       ADJ_TICK
-#define MOD_CLKA       ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
 
 
 /*
@@ -169,9 +172,13 @@ struct timex {
 #define STA_PPSERROR   0x0800  /* PPS signal calibration error (ro) */
 
 #define STA_CLOCKERR   0x1000  /* clock hardware fault (ro) */
+#define STA_NANO       0x2000  /* resolution (0 = us, 1 = ns) (ro) */
+#define STA_MODE       0x4000  /* mode (0 = PLL, 1 = FLL) (ro) */
+#define STA_CLK                0x8000  /* clock source (0 = A, 1 = B) (ro) */
 
+/* read-only bits */
 #define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
-    STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
+       STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)
 
 /*
  * Clock states (time_state)
@@ -203,10 +210,9 @@ extern int time_status;            /* clock synchronization status bits */
 extern long time_maxerror;     /* maximum error */
 extern long time_esterror;     /* estimated error */
 
-extern long time_freq;         /* frequency offset (scaled ppm) */
-
 extern long time_adjust;       /* The amount of adjtime left */
 
+extern void ntp_init(void);
 extern void ntp_clear(void);
 
 /**
@@ -225,7 +231,7 @@ static inline int ntp_synced(void)
        __x < 0 ? -(-__x >> __s) : __x >> __s;  \
 })
 
-#define TICK_LENGTH_SHIFT      32
+#define NTP_SCALE_SHIFT                32
 
 #ifdef CONFIG_NO_HZ
 #define NTP_INTERVAL_FREQ  (2)
@@ -234,8 +240,8 @@ static inline int ntp_synced(void)
 #endif
 #define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
 
-/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
-extern u64 current_tick_length(void);
+/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
+extern u64 tick_length;
 
 extern void second_overflow(void);
 extern void update_ntp_one_tick(void);
diff --git a/include/linux/usb/c67x00.h b/include/linux/usb/c67x00.h
new file mode 100644 (file)
index 0000000..83c6b45
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * usb_c67x00.h: platform definitions for the Cypress C67X00 USB chip
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#ifndef _LINUX_USB_C67X00_H
+#define _LINUX_USB_C67X00_H
+
+/* SIE configuration */
+#define C67X00_SIE_UNUSED      0
+#define C67X00_SIE_HOST                1
+#define C67X00_SIE_PERIPHERAL_A        2       /* peripheral on A port */
+#define C67X00_SIE_PERIPHERAL_B        3       /* peripheral on B port */
+
+#define c67x00_sie_config(config, n)  (((config)>>(4*(n)))&0x3)
+
+#define C67X00_SIE1_UNUSED             (C67X00_SIE_UNUSED              << 0)
+#define C67X00_SIE1_HOST               (C67X00_SIE_HOST                << 0)
+#define C67X00_SIE1_PERIPHERAL_A       (C67X00_SIE_PERIPHERAL_A        << 0)
+#define C67X00_SIE1_PERIPHERAL_B       (C67X00_SIE_PERIPHERAL_B        << 0)
+
+#define C67X00_SIE2_UNUSED             (C67X00_SIE_UNUSED              << 4)
+#define C67X00_SIE2_HOST               (C67X00_SIE_HOST                << 4)
+#define C67X00_SIE2_PERIPHERAL_A       (C67X00_SIE_PERIPHERAL_A        << 4)
+#define C67X00_SIE2_PERIPHERAL_B       (C67X00_SIE_PERIPHERAL_B        << 4)
+
+struct c67x00_platform_data {
+       int sie_config;                 /* SIEs config (C67X00_SIEx_*) */
+       unsigned long hpi_regstep;      /* Step between HPI registers  */
+};
+
+#endif /* _LINUX_USB_C67X00_H */
index 7e0d3084f76c8411aa5dad0b09772f840020b50a..73a2f4eb1f7ae1a6f9c23131a56f5d1d6d631d58 100644 (file)
@@ -455,7 +455,7 @@ struct usb_encryption_descriptor {
 
 /*-------------------------------------------------------------------------*/
 
-/* USB_DT_BOS:  group of wireless capabilities */
+/* USB_DT_BOS:  group of device-level capabilities */
 struct usb_bos_descriptor {
        __u8  bLength;
        __u8  bDescriptorType;
@@ -501,6 +501,16 @@ struct usb_wireless_cap_descriptor {       /* Ultra Wide Band */
        __u8  bReserved;
 } __attribute__((packed));
 
+#define        USB_CAP_TYPE_EXT                2
+
+struct usb_ext_cap_descriptor {                /* Link Power Management */
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDevCapabilityType;
+       __u8  bmAttributes;
+#define USB_LPM_SUPPORT                        (1 << 1)        /* supports LPM */
+} __attribute__((packed));
+
 /*-------------------------------------------------------------------------*/
 
 /* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
index d8128f7102c92858bc01d71c7544882849318ae7..cf468fbdbf8e80b504ecb3ac1d798120c066ca2f 100644 (file)
@@ -114,6 +114,8 @@ struct usb_ep_ops {
        int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
 
        int (*set_halt) (struct usb_ep *ep, int value);
+       int (*set_wedge) (struct usb_ep *ep);
+
        int (*fifo_status) (struct usb_ep *ep);
        void (*fifo_flush) (struct usb_ep *ep);
 };
@@ -348,6 +350,25 @@ static inline int usb_ep_clear_halt(struct usb_ep *ep)
        return ep->ops->set_halt(ep, 0);
 }
 
+/**
+ * usb_ep_set_wedge - sets the halt feature and ignores clear requests
+ * @ep: the endpoint being wedged
+ *
+ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
+ * requests. If the gadget driver clears the halt status, it will
+ * automatically unwedge the endpoint.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_ep_set_wedge(struct usb_ep *ep)
+{
+       if (ep->ops->set_wedge)
+               return ep->ops->set_wedge(ep);
+       else
+               return ep->ops->set_halt(ep, 1);
+}
+
 /**
  * usb_ep_fifo_status - returns number of bytes in fifo, or error
  * @ep: the endpoint whose fifo status is being checked.
index e7d10845b3c17be5c8bf26fa088a5c82c92e3af4..06005fa9e982e0f703a7eef56f4108378c566f24 100644 (file)
@@ -76,6 +76,7 @@ struct virtqueue_ops {
  * @dev: underlying device.
  * @id: the device type identification (used to match it with a driver).
  * @config: the configuration ops for this device.
+ * @features: the features supported by both driver and device.
  * @priv: private pointer for the driver's use.
  */
 struct virtio_device
@@ -84,6 +85,8 @@ struct virtio_device
        struct device dev;
        struct virtio_device_id id;
        struct virtio_config_ops *config;
+       /* Note that this is a Linux set_bit-style bitmap. */
+       unsigned long features[1];
        void *priv;
 };
 
@@ -94,6 +97,8 @@ void unregister_virtio_device(struct virtio_device *dev);
  * virtio_driver - operations for a virtio I/O driver
  * @driver: underlying device driver (populate name and owner).
  * @id_table: the ids serviced by this driver.
+ * @feature_table: an array of feature numbers supported by this device.
+ * @feature_table_size: number of entries in the feature table array.
  * @probe: the function to call when a device is found.  Returns a token for
  *    remove, or PTR_ERR().
  * @remove: the function when a device is removed.
@@ -103,6 +108,8 @@ void unregister_virtio_device(struct virtio_device *dev);
 struct virtio_driver {
        struct device_driver driver;
        const struct virtio_device_id *id_table;
+       const unsigned int *feature_table;
+       unsigned int feature_table_size;
        int (*probe)(struct virtio_device *dev);
        void (*remove)(struct virtio_device *dev);
        void (*config_changed)(struct virtio_device *dev);
index bca0b10d79470056cc6456101ef45454f813149f..d4695a3356d018f4198df0d5813070cc4b5cf5ad 100644 (file)
@@ -9,6 +9,7 @@
 #define VIRTIO_BLK_F_BARRIER   0       /* Does host support barriers? */
 #define VIRTIO_BLK_F_SIZE_MAX  1       /* Indicates maximum segment size */
 #define VIRTIO_BLK_F_SEG_MAX   2       /* Indicates maximum # of segments */
+#define VIRTIO_BLK_F_GEOMETRY  4       /* Legacy geometry available  */
 
 struct virtio_blk_config
 {
@@ -18,6 +19,12 @@ struct virtio_blk_config
        __le32 size_max;
        /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
        __le32 seg_max;
+       /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+       struct virtio_blk_geometry {
+               __le16 cylinders;
+               __u8 heads;
+               __u8 sectors;
+       } geometry;
 } __attribute__((packed));
 
 /* These two define direction. */
@@ -41,13 +48,8 @@ struct virtio_blk_outhdr
        __u64 sector;
 };
 
+/* And this is the final byte of the write scatter-gather list. */
 #define VIRTIO_BLK_S_OK                0
 #define VIRTIO_BLK_S_IOERR     1
 #define VIRTIO_BLK_S_UNSUPP    2
-
-/* This is the first element of the write scatter-gather list */
-struct virtio_blk_inhdr
-{
-       unsigned char status;
-};
 #endif /* _LINUX_VIRTIO_BLK_H */
index d581b2914b342cbbe83744bc15762fb8718a81a3..50db245c81ad94f1131d88b512c100219475717b 100644 (file)
 #define VIRTIO_CONFIG_S_FAILED         0x80
 
 #ifdef __KERNEL__
-struct virtio_device;
+#include <linux/virtio.h>
 
 /**
  * virtio_config_ops - operations for configuring a virtio device
- * @feature: search for a feature in this config
- *     vdev: the virtio_device
- *     bit: the feature bit
- *     Returns true if the feature is supported.  Acknowledges the feature
- *     so the host can see it.
  * @get: read the value of a configuration field
  *     vdev: the virtio_device
  *     offset: the offset of the configuration field
  *     buf: the buffer to write the field value into.
  *     len: the length of the buffer
- *     Note that contents are conventionally little-endian.
  * @set: write the value of a configuration field
  *     vdev: the virtio_device
  *     offset: the offset of the configuration field
  *     buf: the buffer to read the field value from.
  *     len: the length of the buffer
- *     Note that contents are conventionally little-endian.
  * @get_status: read the status byte
  *     vdev: the virtio_device
  *     Returns the status byte
@@ -52,10 +45,15 @@ struct virtio_device;
  *     callback: the virqtueue callback
  *     Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
  * @del_vq: free a virtqueue found by find_vq().
+ * @get_features: get the array of feature bits for this device.
+ *     vdev: the virtio_device
+ *     Returns the first 32 feature bits (all we currently need).
+ * @set_features: confirm what device features we'll be using.
+ *     vdev: the virtio_device
+ *     feature: the first 32 feature bits
  */
 struct virtio_config_ops
 {
-       bool (*feature)(struct virtio_device *vdev, unsigned bit);
        void (*get)(struct virtio_device *vdev, unsigned offset,
                    void *buf, unsigned len);
        void (*set)(struct virtio_device *vdev, unsigned offset,
@@ -67,43 +65,52 @@ struct virtio_config_ops
                                     unsigned index,
                                     void (*callback)(struct virtqueue *));
        void (*del_vq)(struct virtqueue *vq);
+       u32 (*get_features)(struct virtio_device *vdev);
+       void (*set_features)(struct virtio_device *vdev, u32 features);
 };
 
+/* If driver didn't advertise the feature, it will never appear. */
+void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
+                                        unsigned int fbit);
+
 /**
- * virtio_config_val - look for a feature and get a single virtio config.
- * @vdev: the virtio device
+ * virtio_has_feature - helper to determine if this device has this feature.
+ * @vdev: the device
  * @fbit: the feature bit
- * @offset: the type to search for.
- * @val: a pointer to the value to fill in.
- *
- * The return value is -ENOENT if the feature doesn't exist.  Otherwise
- * the value is endian-corrected and returned in v. */
-#define virtio_config_val(vdev, fbit, offset, v) ({                    \
-       int _err;                                                       \
-       if ((vdev)->config->feature((vdev), (fbit))) {                  \
-               __virtio_config_val((vdev), (offset), (v));             \
-               _err = 0;                                               \
-       } else                                                          \
-               _err = -ENOENT;                                         \
-       _err;                                                           \
-})
+ */
+static inline bool virtio_has_feature(const struct virtio_device *vdev,
+                                     unsigned int fbit)
+{
+       /* Did you forget to fix assumptions on max features? */
+       if (__builtin_constant_p(fbit))
+               BUILD_BUG_ON(fbit >= 32);
+
+       virtio_check_driver_offered_feature(vdev, fbit);
+       return test_bit(fbit, vdev->features);
+}
 
 /**
- * __virtio_config_val - get a single virtio config without feature check.
+ * virtio_config_val - look for a feature and get a virtio config entry.
  * @vdev: the virtio device
+ * @fbit: the feature bit
  * @offset: the type to search for.
  * @val: a pointer to the value to fill in.
  *
- * The value is endian-corrected and returned in v. */
-#define __virtio_config_val(vdev, offset, v) do {                      \
-       BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2             \
-                    && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);        \
-       (vdev)->config->get((vdev), (offset), (v), sizeof(*(v)));       \
-       switch (sizeof(*(v))) {                                         \
-       case 2: le16_to_cpus((__u16 *) v); break;                       \
-       case 4: le32_to_cpus((__u32 *) v); break;                       \
-       case 8: le64_to_cpus((__u64 *) v); break;                       \
-       }                                                               \
-} while(0)
+ * The return value is -ENOENT if the feature doesn't exist.  Otherwise
+ * the config value is copied into whatever is pointed to by v. */
+#define virtio_config_val(vdev, fbit, offset, v) \
+       virtio_config_buf((vdev), (fbit), (offset), (v), sizeof(v))
+
+static inline int virtio_config_buf(struct virtio_device *vdev,
+                                   unsigned int fbit,
+                                   unsigned int offset,
+                                   void *buf, unsigned len)
+{
+       if (!virtio_has_feature(vdev, fbit))
+               return -ENOENT;
+
+       vdev->config->get(vdev, offset, buf, len);
+       return 0;
+}
 #endif /* __KERNEL__ */
 #endif /* _LINUX_VIRTIO_CONFIG_H */
index 1ea3351df609474d097b67e4f0df31131257a34f..9405aa6cdf2672d40375bfa4bfb4ae90ce86e335 100644 (file)
@@ -6,9 +6,18 @@
 #define VIRTIO_ID_NET  1
 
 /* The feature bitmap for virtio net */
-#define VIRTIO_NET_F_CSUM      0       /* Can handle pkts w/ partial csum */
+#define VIRTIO_NET_F_CSUM      0       /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM        1       /* Guest handles pkts w/ partial csum */
 #define VIRTIO_NET_F_MAC       5       /* Host has given MAC address. */
-#define VIRTIO_NET_F_GSO       6       /* Can handle pkts w/ any GSO type */
+#define VIRTIO_NET_F_GSO       6       /* Host handles pkts w/ any GSO type */
+#define VIRTIO_NET_F_GUEST_TSO4        7       /* Guest can handle TSOv4 in. */
+#define VIRTIO_NET_F_GUEST_TSO6        8       /* Guest can handle TSOv6 in. */
+#define VIRTIO_NET_F_GUEST_ECN 9       /* Guest can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_GUEST_UFO 10      /* Guest can handle UFO in. */
+#define VIRTIO_NET_F_HOST_TSO4 11      /* Host can handle TSOv4 in. */
+#define VIRTIO_NET_F_HOST_TSO6 12      /* Host can handle TSOv6 in. */
+#define VIRTIO_NET_F_HOST_ECN  13      /* Host can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_HOST_UFO  14      /* Host can handle UFO in. */
 
 struct virtio_net_config
 {
index 1f74bcd603fedaee2d513758add2ebe4d827fea6..32742c4563de22131a6abce886ff2d8ff5629724 100644 (file)
 #define SCSI_MAX_SG_CHAIN_SEGMENTS     SCSI_MAX_SG_SEGMENTS
 #endif
 
-/*
- *     SCSI command lengths
- */
-
-extern const unsigned char scsi_command_size[8];
-#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
-
 /*
  * Special value for scanning to specify scanning or rescanning of all
  * possible channels, (target) ids, or luns on a given shost.
@@ -109,6 +102,7 @@ extern const unsigned char scsi_command_size[8];
 #define MODE_SENSE_10         0x5a
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define VARIABLE_LENGTH_CMD   0x7f
 #define REPORT_LUNS           0xa0
 #define MAINTENANCE_IN        0xa3
 #define MOVE_MEDIUM           0xa5
@@ -135,6 +129,38 @@ extern const unsigned char scsi_command_size[8];
 #define        ATA_16                0x85      /* 16-byte pass-thru */
 #define        ATA_12                0xa1      /* 12-byte pass-thru */
 
+/*
+ *     SCSI command lengths
+ */
+
+#define SCSI_MAX_VARLEN_CDB_SIZE 260
+
+/* defined in T10 SCSI Primary Commands-2 (SPC2) */
+struct scsi_varlen_cdb_hdr {
+       u8 opcode;        /* opcode always == VARIABLE_LENGTH_CMD */
+       u8 control;
+       u8 misc[5];
+       u8 additional_cdb_length;         /* total cdb length - 8 */
+       __be16 service_action;
+       /* service specific data follows */
+};
+
+static inline unsigned
+scsi_varlen_cdb_length(const void *hdr)
+{
+       return ((struct scsi_varlen_cdb_hdr *)hdr)->additional_cdb_length + 8;
+}
+
+extern const unsigned char scsi_command_size_tbl[8];
+#define COMMAND_SIZE(opcode) scsi_command_size_tbl[((opcode) >> 5) & 7]
+
+static inline unsigned
+scsi_command_size(const unsigned char *cmnd)
+{
+       return (cmnd[0] == VARIABLE_LENGTH_CMD) ?
+               scsi_varlen_cdb_length(cmnd) : COMMAND_SIZE(cmnd[0]);
+}
+
 /*
  *  SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
  *  T10/1561-D Revision 4 Draft dated 7th November 2002.
index 8d20e60a94b7e18b25f8d1c44d393635cd892211..3e46dfae81940dd889262c0fb22a4f0730fff413 100644 (file)
@@ -7,10 +7,28 @@
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/scatterlist.h>
+#include <linux/blkdev.h>
 
 struct Scsi_Host;
 struct scsi_device;
 
+/*
+ * MAX_COMMAND_SIZE is:
+ * The longest fixed-length SCSI CDB as per the SCSI standard.
+ * fixed-length means: commands that their size can be determined
+ * by their opcode and the CDB does not carry a length specifier, (unlike
+ * the VARIABLE_LENGTH_CMD(0x7f) command). This is actually not exactly
+ * true and the SCSI standard also defines extended commands and
+ * vendor specific commands that can be bigger than 16 bytes. The kernel
+ * will support these using the same infrastructure used for VARLEN CDB's.
+ * So in effect MAX_COMMAND_SIZE means the maximum size command scsi-ml
+ * supports without specifying a cmd_len by ULD's
+ */
+#define MAX_COMMAND_SIZE 16
+#if (MAX_COMMAND_SIZE > BLK_MAX_CDB)
+# error MAX_COMMAND_SIZE can not be bigger than BLK_MAX_CDB
+#endif
+
 struct scsi_data_buffer {
        struct sg_table table;
        unsigned length;
@@ -60,12 +78,11 @@ struct scsi_cmnd {
        int allowed;
        int timeout_per_command;
 
-       unsigned char cmd_len;
+       unsigned short cmd_len;
        enum dma_data_direction sc_data_direction;
 
        /* These elements define the operation we are about to perform */
-#define MAX_COMMAND_SIZE       16
-       unsigned char cmnd[MAX_COMMAND_SIZE];
+       unsigned char *cmnd;
 
        struct timer_list eh_timeout;   /* Used to time out the command. */
 
index d3a133b4a072bf2104a0204d29084be7b79bd186..2a9add21267d7fddfc4f443b6d5f475eba65b31e 100644 (file)
@@ -75,11 +75,11 @@ struct scsi_eh_save {
        int result;
        enum dma_data_direction data_direction;
        unsigned char cmd_len;
-       unsigned char cmnd[MAX_COMMAND_SIZE];
+       unsigned char *cmnd;
        struct scsi_data_buffer sdb;
        struct request *next_rq;
-
        /* new command support */
+       unsigned char eh_cmnd[BLK_MAX_CDB];
        struct scatterlist sense_sgl;
 };
 
index d967d6dc7a28d7de7d58eb40b4a2258c4187c2a8..1834fdfe82a7d7129880e2a0380c2e99b77adfa3 100644 (file)
@@ -573,13 +573,11 @@ struct Scsi_Host {
        /*
         * The maximum length of SCSI commands that this host can accept.
         * Probably 12 for most host adapters, but could be 16 for others.
+        * or 260 if the driver supports variable length cdbs.
         * For drivers that don't set this field, a value of 12 is
-        * assumed.  I am leaving this as a number rather than a bit
-        * because you never know what subsequent SCSI standards might do
-        * (i.e. could there be a 20 byte or a 24-byte command a few years
-        * down the road?).  
+        * assumed.
         */
-       unsigned char max_cmd_len;
+       unsigned short max_cmd_len;
 
        int this_id;
        int can_queue;
index 4a856a3643bb3f3ba3f99f6183bd8400b3f97eb9..32c254a8ab9af07ae3ac102972063956592e0b3b 100644 (file)
@@ -955,7 +955,8 @@ asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
                        __put_user(txc.jitcnt, &utp->jitcnt) ||
                        __put_user(txc.calcnt, &utp->calcnt) ||
                        __put_user(txc.errcnt, &utp->errcnt) ||
-                       __put_user(txc.stbcnt, &utp->stbcnt))
+                       __put_user(txc.stbcnt, &utp->stbcnt) ||
+                       __put_user(txc.tai, &utp->tai))
                ret = -EFAULT;
 
        return ret;
index d3ad54677f9c0257fa0a373f8ce1b4774e947722..1510f78a0ffa5a9496604b3acee679ca63d93c99 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/acct.h>
 #include <linux/tsacct_kern.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/binfmts.h>
 #include <linux/nsproxy.h>
 #include <linux/pid_namespace.h>
index 2bb675af4de30908b2dd1a22e745541e2bcbc3f5..933e60ebccae9f35001753a4426993c6aaf54fb6 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mempolicy.h>
 #include <linux/sem.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/key.h>
 #include <linux/binfmts.h>
 #include <linux/mman.h>
index 46e4ad1723f0545377c342c57a988a5ff99fef9c..46d6611a33bbe4a7997637168feb543acd0f0b8e 100644 (file)
@@ -150,6 +150,26 @@ void disable_irq(unsigned int irq)
 }
 EXPORT_SYMBOL(disable_irq);
 
+static void __enable_irq(struct irq_desc *desc, unsigned int irq)
+{
+       switch (desc->depth) {
+       case 0:
+               printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
+               WARN_ON(1);
+               break;
+       case 1: {
+               unsigned int status = desc->status & ~IRQ_DISABLED;
+
+               /* Prevent probing on this irq: */
+               desc->status = status | IRQ_NOPROBE;
+               check_irq_resend(desc, irq);
+               /* fall-through */
+       }
+       default:
+               desc->depth--;
+       }
+}
+
 /**
  *     enable_irq - enable handling of an irq
  *     @irq: Interrupt to enable
@@ -169,22 +189,7 @@ void enable_irq(unsigned int irq)
                return;
 
        spin_lock_irqsave(&desc->lock, flags);
-       switch (desc->depth) {
-       case 0:
-               printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
-               WARN_ON(1);
-               break;
-       case 1: {
-               unsigned int status = desc->status & ~IRQ_DISABLED;
-
-               /* Prevent probing on this irq: */
-               desc->status = status | IRQ_NOPROBE;
-               check_irq_resend(desc, irq);
-               /* fall-through */
-       }
-       default:
-               desc->depth--;
-       }
+       __enable_irq(desc, irq);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 EXPORT_SYMBOL(enable_irq);
@@ -365,7 +370,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                        compat_irq_chip_set_default_handler(desc);
 
                desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
-                                 IRQ_INPROGRESS);
+                                 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
 
                if (!(desc->status & IRQ_NOAUTOEN)) {
                        desc->depth = 0;
@@ -381,6 +386,16 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        /* Reset broken irq detection when installing new handler */
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
+
+       /*
+        * Check whether we disabled the irq via the spurious handler
+        * before. Reenable it and give it another chance.
+        */
+       if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
+               desc->status &= ~IRQ_SPURIOUS_DISABLED;
+               __enable_irq(desc, irq);
+       }
+
        spin_unlock_irqrestore(&desc->lock, flags);
 
        new->irq = irq;
index 088dabbf2d6a6cbca786ec80fe0ce6851175fef9..c66d3f10e85326ab1041a29202047734769b9b10 100644 (file)
@@ -209,8 +209,8 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
                 * Now kill the IRQ
                 */
                printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
-               desc->status |= IRQ_DISABLED;
-               desc->depth = 1;
+               desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED;
+               desc->depth++;
                desc->chip->disable(irq);
        }
        desc->irqs_unhandled = 0;
index cb85c79989b440a3979e3d2e6dd3bcfa198b1c3b..1c5fcacbcf336b8dc82d0b02202a3d95c32fbd13 100644 (file)
@@ -1217,7 +1217,7 @@ static int __init parse_crashkernel_mem(char                      *cmdline,
                }
 
                /* match ? */
-               if (system_ram >= start && system_ram <= end) {
+               if (system_ram >= start && system_ram < end) {
                        *crash_size = size;
                        break;
                }
index e2764047ec03ed123acd3546ff4357341302cabb..8df97d3dfda8611423d7cac323cb9ef5dce5170c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mnt_namespace.h>
 #include <linux/completion.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
 #include <linux/mount.h>
index 8d6cccc6c3cf99870f76b00202a2775bd5e2a54f..8674a390a2e8262e10c6fd61a86c40f1ac2079c8 100644 (file)
@@ -164,131 +164,140 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
        return NULL;
 }
 
-static void printk_unused_warning(const char *name)
+static bool always_ok(bool gplok, bool warn, const char *name)
 {
-       printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
-               "however this module is using it.\n", name);
-       printk(KERN_WARNING "This symbol will go away in the future.\n");
-       printk(KERN_WARNING "Please evalute if this is the right api to use, "
-               "and if it really is, submit a report the linux kernel "
-               "mailinglist together with submitting your code for "
-               "inclusion.\n");
+       return true;
 }
 
-/* Find a symbol, return value, crc and module which owns it */
-static unsigned long __find_symbol(const char *name,
-                                  struct module **owner,
-                                  const unsigned long **crc,
-                                  int gplok)
+static bool printk_unused_warning(bool gplok, bool warn, const char *name)
 {
-       struct module *mod;
-       const struct kernel_symbol *ks;
-
-       /* Core kernel first. */
-       *owner = NULL;
-       ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
-       if (ks) {
-               *crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
-               return ks->value;
+       if (warn) {
+               printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
+                      "however this module is using it.\n", name);
+               printk(KERN_WARNING
+                      "This symbol will go away in the future.\n");
+               printk(KERN_WARNING
+                      "Please evalute if this is the right api to use and if "
+                      "it really is, submit a report the linux kernel "
+                      "mailinglist together with submitting your code for "
+                      "inclusion.\n");
        }
-       if (gplok) {
-               ks = lookup_symbol(name, __start___ksymtab_gpl,
-                                        __stop___ksymtab_gpl);
-               if (ks) {
-                       *crc = symversion(__start___kcrctab_gpl,
-                                         (ks - __start___ksymtab_gpl));
-                       return ks->value;
-               }
-       }
-       ks = lookup_symbol(name, __start___ksymtab_gpl_future,
-                                __stop___ksymtab_gpl_future);
-       if (ks) {
-               if (!gplok) {
-                       printk(KERN_WARNING "Symbol %s is being used "
-                              "by a non-GPL module, which will not "
-                              "be allowed in the future\n", name);
-                       printk(KERN_WARNING "Please see the file "
-                              "Documentation/feature-removal-schedule.txt "
-                              "in the kernel source tree for more "
-                              "details.\n");
-               }
-               *crc = symversion(__start___kcrctab_gpl_future,
-                                 (ks - __start___ksymtab_gpl_future));
-               return ks->value;
+       return true;
+}
+
+static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name)
+{
+       if (!gplok)
+               return false;
+       return printk_unused_warning(gplok, warn, name);
+}
+
+static bool gpl_only(bool gplok, bool warn, const char *name)
+{
+       return gplok;
+}
+
+static bool warn_if_not_gpl(bool gplok, bool warn, const char *name)
+{
+       if (!gplok && warn) {
+               printk(KERN_WARNING "Symbol %s is being used "
+                      "by a non-GPL module, which will not "
+                      "be allowed in the future\n", name);
+               printk(KERN_WARNING "Please see the file "
+                      "Documentation/feature-removal-schedule.txt "
+                      "in the kernel source tree for more details.\n");
        }
+       return true;
+}
 
-       ks = lookup_symbol(name, __start___ksymtab_unused,
-                                __stop___ksymtab_unused);
-       if (ks) {
-               printk_unused_warning(name);
-               *crc = symversion(__start___kcrctab_unused,
-                                 (ks - __start___ksymtab_unused));
-               return ks->value;
+struct symsearch {
+       const struct kernel_symbol *start, *stop;
+       const unsigned long *crcs;
+       bool (*check)(bool gplok, bool warn, const char *name);
+};
+
+/* Look through this array of symbol tables for a symbol match which
+ * passes the check function. */
+static const struct kernel_symbol *search_symarrays(const struct symsearch *arr,
+                                                   unsigned int num,
+                                                   const char *name,
+                                                   bool gplok,
+                                                   bool warn,
+                                                   const unsigned long **crc)
+{
+       unsigned int i;
+       const struct kernel_symbol *ks;
+
+       for (i = 0; i < num; i++) {
+               ks = lookup_symbol(name, arr[i].start, arr[i].stop);
+               if (!ks || !arr[i].check(gplok, warn, name))
+                       continue;
+
+               if (crc)
+                       *crc = symversion(arr[i].crcs, ks - arr[i].start);
+               return ks;
        }
+       return NULL;
+}
+
+/* Find a symbol, return value, (optional) crc and (optional) module
+ * which owns it */
+static unsigned long find_symbol(const char *name,
+                                struct module **owner,
+                                const unsigned long **crc,
+                                bool gplok,
+                                bool warn)
+{
+       struct module *mod;
+       const struct kernel_symbol *ks;
+       const struct symsearch arr[] = {
+               { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
+                 always_ok },
+               { __start___ksymtab_gpl, __stop___ksymtab_gpl,
+                 __start___kcrctab_gpl, gpl_only },
+               { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
+                 __start___kcrctab_gpl_future, warn_if_not_gpl },
+               { __start___ksymtab_unused, __stop___ksymtab_unused,
+                 __start___kcrctab_unused, printk_unused_warning },
+               { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
+                 __start___kcrctab_unused_gpl, gpl_only_unused_warning },
+       };
 
-       if (gplok)
-               ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
-                                __stop___ksymtab_unused_gpl);
+       /* Core kernel first. */
+       ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc);
        if (ks) {
-               printk_unused_warning(name);
-               *crc = symversion(__start___kcrctab_unused_gpl,
-                                 (ks - __start___ksymtab_unused_gpl));
+               if (owner)
+                       *owner = NULL;
                return ks->value;
        }
 
        /* Now try modules. */
        list_for_each_entry(mod, &modules, list) {
-               *owner = mod;
-               ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
-               if (ks) {
-                       *crc = symversion(mod->crcs, (ks - mod->syms));
-                       return ks->value;
-               }
-
-               if (gplok) {
-                       ks = lookup_symbol(name, mod->gpl_syms,
-                                          mod->gpl_syms + mod->num_gpl_syms);
-                       if (ks) {
-                               *crc = symversion(mod->gpl_crcs,
-                                                 (ks - mod->gpl_syms));
-                               return ks->value;
-                       }
-               }
-               ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
+               struct symsearch arr[] = {
+                       { mod->syms, mod->syms + mod->num_syms, mod->crcs,
+                         always_ok },
+                       { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
+                         mod->gpl_crcs, gpl_only },
+                       { mod->gpl_future_syms,
+                         mod->gpl_future_syms + mod->num_gpl_future_syms,
+                         mod->gpl_future_crcs, warn_if_not_gpl },
+                       { mod->unused_syms,
+                         mod->unused_syms + mod->num_unused_syms,
+                         mod->unused_crcs, printk_unused_warning },
+                       { mod->unused_gpl_syms,
+                         mod->unused_gpl_syms + mod->num_unused_gpl_syms,
+                         mod->unused_gpl_crcs, gpl_only_unused_warning },
+               };
+
+               ks = search_symarrays(arr, ARRAY_SIZE(arr),
+                                     name, gplok, warn, crc);
                if (ks) {
-                       printk_unused_warning(name);
-                       *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
-                       return ks->value;
-               }
-
-               if (gplok) {
-                       ks = lookup_symbol(name, mod->unused_gpl_syms,
-                                          mod->unused_gpl_syms + mod->num_unused_gpl_syms);
-                       if (ks) {
-                               printk_unused_warning(name);
-                               *crc = symversion(mod->unused_gpl_crcs,
-                                                 (ks - mod->unused_gpl_syms));
-                               return ks->value;
-                       }
-               }
-               ks = lookup_symbol(name, mod->gpl_future_syms,
-                                  (mod->gpl_future_syms +
-                                   mod->num_gpl_future_syms));
-               if (ks) {
-                       if (!gplok) {
-                               printk(KERN_WARNING "Symbol %s is being used "
-                                      "by a non-GPL module, which will not "
-                                      "be allowed in the future\n", name);
-                               printk(KERN_WARNING "Please see the file "
-                                      "Documentation/feature-removal-schedule.txt "
-                                      "in the kernel source tree for more "
-                                      "details.\n");
-                       }
-                       *crc = symversion(mod->gpl_future_crcs,
-                                         (ks - mod->gpl_future_syms));
+                       if (owner)
+                               *owner = mod;
                        return ks->value;
                }
        }
+
        DEBUGP("Failed to find symbol %s\n", name);
        return -ENOENT;
 }
@@ -736,12 +745,13 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
        if (!forced && module_refcount(mod) != 0)
                wait_for_zero_refcount(mod);
 
+       mutex_unlock(&module_mutex);
        /* Final destruction now noone is using it. */
-       if (mod->exit != NULL) {
-               mutex_unlock(&module_mutex);
+       if (mod->exit != NULL)
                mod->exit();
-               mutex_lock(&module_mutex);
-       }
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_GOING, mod);
+       mutex_lock(&module_mutex);
        /* Store the name of the last unloaded module for diagnostic purposes */
        strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
        free_module(mod);
@@ -777,10 +787,9 @@ static void print_unload_info(struct seq_file *m, struct module *mod)
 void __symbol_put(const char *symbol)
 {
        struct module *owner;
-       const unsigned long *crc;
 
        preempt_disable();
-       if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1)))
+       if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false)))
                BUG();
        module_put(owner);
        preempt_enable();
@@ -924,13 +933,10 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
                                          struct module *mod)
 {
        const unsigned long *crc;
-       struct module *owner;
 
-       if (IS_ERR_VALUE(__find_symbol("struct_module",
-                                               &owner, &crc, 1)))
+       if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false)))
                BUG();
-       return check_version(sechdrs, versindex, "struct_module", mod,
-                            crc);
+       return check_version(sechdrs, versindex, "struct_module", mod, crc);
 }
 
 /* First part is kernel version, which we ignore. */
@@ -974,8 +980,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
        unsigned long ret;
        const unsigned long *crc;
 
-       ret = __find_symbol(name, &owner, &crc,
-                       !(mod->taints & TAINT_PROPRIETARY_MODULE));
+       ret = find_symbol(name, &owner, &crc,
+                         !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
        if (!IS_ERR_VALUE(ret)) {
                /* use_module can fail due to OOM,
                   or module initialization or unloading */
@@ -991,6 +997,20 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
  * J. Corbet <corbet@lwn.net>
  */
 #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)
+struct module_sect_attr
+{
+       struct module_attribute mattr;
+       char *name;
+       unsigned long address;
+};
+
+struct module_sect_attrs
+{
+       struct attribute_group grp;
+       unsigned int nsections;
+       struct module_sect_attr attrs[0];
+};
+
 static ssize_t module_sect_show(struct module_attribute *mattr,
                                struct module *mod, char *buf)
 {
@@ -1001,7 +1021,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
 
 static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
 {
-       int section;
+       unsigned int section;
 
        for (section = 0; section < sect_attrs->nsections; section++)
                kfree(sect_attrs->attrs[section].name);
@@ -1362,10 +1382,9 @@ void *__symbol_get(const char *symbol)
 {
        struct module *owner;
        unsigned long value;
-       const unsigned long *crc;
 
        preempt_disable();
-       value = __find_symbol(symbol, &owner, &crc, 1);
+       value = find_symbol(symbol, &owner, NULL, true, true);
        if (IS_ERR_VALUE(value))
                value = 0;
        else if (strong_try_module_get(owner))
@@ -1382,33 +1401,33 @@ EXPORT_SYMBOL_GPL(__symbol_get);
  */
 static int verify_export_symbols(struct module *mod)
 {
-       const char *name = NULL;
-       unsigned long i, ret = 0;
+       unsigned int i;
        struct module *owner;
-       const unsigned long *crc;
-
-       for (i = 0; i < mod->num_syms; i++)
-               if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name,
-                                                       &owner, &crc, 1))) {
-                       name = mod->syms[i].name;
-                       ret = -ENOEXEC;
-                       goto dup;
-               }
+       const struct kernel_symbol *s;
+       struct {
+               const struct kernel_symbol *sym;
+               unsigned int num;
+       } arr[] = {
+               { mod->syms, mod->num_syms },
+               { mod->gpl_syms, mod->num_gpl_syms },
+               { mod->gpl_future_syms, mod->num_gpl_future_syms },
+               { mod->unused_syms, mod->num_unused_syms },
+               { mod->unused_gpl_syms, mod->num_unused_gpl_syms },
+       };
 
-       for (i = 0; i < mod->num_gpl_syms; i++)
-               if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name,
-                                                       &owner, &crc, 1))) {
-                       name = mod->gpl_syms[i].name;
-                       ret = -ENOEXEC;
-                       goto dup;
+       for (i = 0; i < ARRAY_SIZE(arr); i++) {
+               for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
+                       if (!IS_ERR_VALUE(find_symbol(s->name, &owner,
+                                                     NULL, true, false))) {
+                               printk(KERN_ERR
+                                      "%s: exports duplicate symbol %s"
+                                      " (owned by %s)\n",
+                                      mod->name, s->name, module_name(owner));
+                               return -ENOEXEC;
+                       }
                }
-
-dup:
-       if (ret)
-               printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n",
-                       mod->name, name, module_name(owner));
-
-       return ret;
+       }
+       return 0;
 }
 
 /* Change all symbols so that st_value encodes the pointer directly. */
@@ -1814,8 +1833,9 @@ static struct module *load_module(void __user *umod,
        unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
 #endif
 
-       /* Don't keep modinfo section */
+       /* Don't keep modinfo and version sections. */
        sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+       sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
 #ifdef CONFIG_KALLSYMS
        /* Keep symbol and string tables for decoding later. */
        sechdrs[symindex].sh_flags |= SHF_ALLOC;
@@ -1977,7 +1997,8 @@ static struct module *load_module(void __user *umod,
                mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
        mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
        if (unusedgplcrcindex)
-               mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
+               mod->unused_gpl_crcs
+                       = (void *)sechdrs[unusedgplcrcindex].sh_addr;
 
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !crcindex) ||
@@ -2171,6 +2192,8 @@ sys_init_module(void __user *umod,
                mod->state = MODULE_STATE_GOING;
                synchronize_sched();
                module_put(mod);
+               blocking_notifier_call_chain(&module_notify_list,
+                                            MODULE_STATE_GOING, mod);
                mutex_lock(&module_mutex);
                free_module(mod);
                mutex_unlock(&module_mutex);
index ae5c6c147c4b37def0b8e3e89f0db9c022d0bc67..f1525ad06cb3ebbb83680b2bc0176854002217ca 100644 (file)
@@ -4,8 +4,9 @@
 
 #include <linux/sched.h>
 #include <linux/posix-timers.h>
-#include <asm/uaccess.h>
 #include <linux/errno.h>
+#include <linux/math64.h>
+#include <asm/uaccess.h>
 
 static int check_clock(const clockid_t which_clock)
 {
@@ -47,12 +48,10 @@ static void sample_to_timespec(const clockid_t which_clock,
                               union cpu_time_count cpu,
                               struct timespec *tp)
 {
-       if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
-               tp->tv_sec = div_long_long_rem(cpu.sched,
-                                              NSEC_PER_SEC, &tp->tv_nsec);
-       } else {
+       if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED)
+               *tp = ns_to_timespec(cpu.sched);
+       else
                cputime_to_timespec(cpu.cpu, tp);
-       }
 }
 
 static inline int cpu_time_before(const clockid_t which_clock,
index dcc199c43a12abcb9e62b4a70e090084d3075fa4..6c19e94fd0a5482786e432599a0fb4840a5c66cb 100644 (file)
@@ -534,7 +534,6 @@ struct task_struct *ptrace_get_task_struct(pid_t pid)
 #define arch_ptrace_attach(child)      do { } while (0)
 #endif
 
-#ifndef __ARCH_SYS_PTRACE
 asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
 {
        struct task_struct *child;
@@ -582,7 +581,6 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
        unlock_kernel();
        return ret;
 }
-#endif /* __ARCH_SYS_PTRACE */
 
 int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
 {
index e2f7f5acc80778328a892961d8e26faa7c4c8841..34bcc5bc120e5f2da970e180dfaf65d73b80dc7d 100644 (file)
@@ -8025,7 +8025,7 @@ static void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
 
        se->my_q = cfs_rq;
        se->load.weight = tg->shares;
-       se->load.inv_weight = div64_64(1ULL<<32, se->load.weight);
+       se->load.inv_weight = div64_u64(1ULL<<32, se->load.weight);
        se->parent = parent;
 }
 #endif
@@ -8692,7 +8692,7 @@ static void __set_se_shares(struct sched_entity *se, unsigned long shares)
                dequeue_entity(cfs_rq, se, 0);
 
        se->load.weight = shares;
-       se->load.inv_weight = div64_64((1ULL<<32), shares);
+       se->load.inv_weight = div64_u64((1ULL<<32), shares);
 
        if (on_rq)
                enqueue_entity(cfs_rq, se, 0);
@@ -8787,7 +8787,7 @@ static unsigned long to_ratio(u64 period, u64 runtime)
        if (runtime == RUNTIME_INF)
                return 1ULL << 16;
 
-       return div64_64(runtime << 16, period);
+       return div64_u64(runtime << 16, period);
 }
 
 #ifdef CONFIG_CGROUP_SCHED
index 8a9498e7c8311e582f35709c7ffc3019fda2f601..6b4a12558e88b94893afeb326c30a21da6269fbf 100644 (file)
@@ -357,8 +357,8 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 
                avg_per_cpu = p->se.sum_exec_runtime;
                if (p->se.nr_migrations) {
-                       avg_per_cpu = div64_64(avg_per_cpu,
-                                              p->se.nr_migrations);
+                       avg_per_cpu = div64_u64(avg_per_cpu,
+                                               p->se.nr_migrations);
                } else {
                        avg_per_cpu = -1LL;
                }
index 3c44956ee7e2312d30f28bc68a5b9825a7da657a..36e0617400470f398700376c7fa3359d768e7e58 100644 (file)
@@ -589,16 +589,20 @@ static void takeover_tasklets(unsigned int cpu)
        local_irq_disable();
 
        /* Find end, append list for that CPU. */
-       *__get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).head;
-       __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail;
-       per_cpu(tasklet_vec, cpu).head = NULL;
-       per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
+       if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) {
+               *(__get_cpu_var(tasklet_vec).tail) = per_cpu(tasklet_vec, cpu).head;
+               __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail;
+               per_cpu(tasklet_vec, cpu).head = NULL;
+               per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
+       }
        raise_softirq_irqoff(TASKLET_SOFTIRQ);
 
-       *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head;
-       __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail;
-       per_cpu(tasklet_hi_vec, cpu).head = NULL;
-       per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
+       if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) {
+               *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head;
+               __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail;
+               per_cpu(tasklet_hi_vec, cpu).head = NULL;
+               per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
+       }
        raise_softirq_irqoff(HI_SOFTIRQ);
 
        local_irq_enable();
index 86729042e4cd067b1168fe8ed5cc2da01576cf03..cbe0d5a222ff8727286701b90099528a533cfc73 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/security.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/math64.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -391,13 +392,17 @@ EXPORT_SYMBOL(set_normalized_timespec);
 struct timespec ns_to_timespec(const s64 nsec)
 {
        struct timespec ts;
+       s32 rem;
 
        if (!nsec)
                return (struct timespec) {0, 0};
 
-       ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC, &ts.tv_nsec);
-       if (unlikely(nsec < 0))
-               set_normalized_timespec(&ts, ts.tv_sec, ts.tv_nsec);
+       ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
+       if (unlikely(rem < 0)) {
+               ts.tv_sec--;
+               rem += NSEC_PER_SEC;
+       }
+       ts.tv_nsec = rem;
 
        return ts;
 }
@@ -527,8 +532,10 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
         * Convert jiffies to nanoseconds and separate with
         * one divide.
         */
-       u64 nsec = (u64)jiffies * TICK_NSEC;
-       value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_nsec);
+       u32 rem;
+       value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
+                                   NSEC_PER_SEC, &rem);
+       value->tv_nsec = rem;
 }
 EXPORT_SYMBOL(jiffies_to_timespec);
 
@@ -566,12 +573,11 @@ void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value)
         * Convert jiffies to nanoseconds and separate with
         * one divide.
         */
-       u64 nsec = (u64)jiffies * TICK_NSEC;
-       long tv_usec;
+       u32 rem;
 
-       value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tv_usec);
-       tv_usec /= NSEC_PER_USEC;
-       value->tv_usec = tv_usec;
+       value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
+                                   NSEC_PER_SEC, &rem);
+       value->tv_usec = rem / NSEC_PER_USEC;
 }
 EXPORT_SYMBOL(jiffies_to_timeval);
 
@@ -587,9 +593,7 @@ clock_t jiffies_to_clock_t(long x)
        return x / (HZ / USER_HZ);
 # endif
 #else
-       u64 tmp = (u64)x * TICK_NSEC;
-       do_div(tmp, (NSEC_PER_SEC / USER_HZ));
-       return (long)tmp;
+       return div_u64((u64)x * TICK_NSEC, NSEC_PER_SEC / USER_HZ);
 #endif
 }
 EXPORT_SYMBOL(jiffies_to_clock_t);
@@ -601,16 +605,12 @@ unsigned long clock_t_to_jiffies(unsigned long x)
                return ~0UL;
        return x * (HZ / USER_HZ);
 #else
-       u64 jif;
-
        /* Don't worry about loss of precision here .. */
        if (x >= ~0UL / HZ * USER_HZ)
                return ~0UL;
 
        /* .. but do try to contain it here */
-       jif = x * (u64) HZ;
-       do_div(jif, USER_HZ);
-       return jif;
+       return div_u64((u64)x * HZ, USER_HZ);
 #endif
 }
 EXPORT_SYMBOL(clock_t_to_jiffies);
@@ -619,10 +619,9 @@ 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);
+       x = div_u64(x * USER_HZ, HZ);
 # elif HZ > USER_HZ
-       do_div(x, HZ / USER_HZ);
+       x = div_u64(x, HZ / USER_HZ);
 # else
        /* Nothing to do */
 # endif
@@ -632,8 +631,7 @@ u64 jiffies_64_to_clock_t(u64 x)
         * but even this doesn't overflow in hundreds of years
         * in 64 bits, so..
         */
-       x *= TICK_NSEC;
-       do_div(x, (NSEC_PER_SEC / USER_HZ));
+       x = div_u64(x * TICK_NSEC, (NSEC_PER_SEC / USER_HZ));
 #endif
        return x;
 }
@@ -642,21 +640,17 @@ EXPORT_SYMBOL(jiffies_64_to_clock_t);
 u64 nsec_to_clock_t(u64 x)
 {
 #if (NSEC_PER_SEC % USER_HZ) == 0
-       do_div(x, (NSEC_PER_SEC / USER_HZ));
+       return div_u64(x, NSEC_PER_SEC / USER_HZ);
 #elif (USER_HZ % 512) == 0
-       x *= USER_HZ/512;
-       do_div(x, (NSEC_PER_SEC / 512));
+       return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512);
 #else
        /*
          * max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024,
          * overflow after 64.99 years.
          * exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ...
          */
-       x *= 9;
-       do_div(x, (unsigned long)((9ull * NSEC_PER_SEC + (USER_HZ/2)) /
-                                 USER_HZ));
+       return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
 #endif
-       return x;
 }
 
 #if (BITS_PER_LONG < 64)
index 5fd9b946977038cbdc192dc5a11146696ad53947..5125ddd8196ba3cffb2fd683c2fd3abdac0a695b 100644 (file)
@@ -15,7 +15,8 @@
 #include <linux/jiffies.h>
 #include <linux/hrtimer.h>
 #include <linux/capability.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
+#include <linux/clocksource.h>
 #include <asm/timex.h>
 
 /*
  */
 unsigned long tick_usec = TICK_USEC;           /* USER_HZ period (usec) */
 unsigned long tick_nsec;                       /* ACTHZ period (nsec) */
-static u64 tick_length, tick_length_base;
+u64 tick_length;
+static u64 tick_length_base;
+
+static struct hrtimer leap_timer;
 
 #define MAX_TICKADJ            500             /* microsecs */
 #define MAX_TICKADJ_SCALED     (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \
-                                 TICK_LENGTH_SHIFT) / NTP_INTERVAL_FREQ)
+                                 NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
 
 /*
  * phase-lock loop variables
@@ -35,11 +39,12 @@ static u64 tick_length, tick_length_base;
 /* TIME_ERROR prevents overwriting the CMOS clock */
 static int time_state = TIME_OK;       /* clock synchronization status */
 int time_status = STA_UNSYNC;          /* clock status bits            */
-static s64 time_offset;                /* time adjustment (ns)         */
+static long time_tai;                  /* TAI offset (s)               */
+static s64 time_offset;                        /* time adjustment (ns)         */
 static long time_constant = 2;         /* pll time constant            */
 long time_maxerror = NTP_PHASE_LIMIT;  /* maximum error (us)           */
 long time_esterror = NTP_PHASE_LIMIT;  /* estimated error (us)         */
-long time_freq;                                /* frequency offset (scaled ppm)*/
+static s64 time_freq;                  /* frequency offset (scaled ns/s)*/
 static long time_reftime;              /* time at last adjustment (s)  */
 long time_adjust;
 static long ntp_tick_adj;
@@ -47,16 +52,56 @@ static long ntp_tick_adj;
 static void ntp_update_frequency(void)
 {
        u64 second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)
-                               << TICK_LENGTH_SHIFT;
-       second_length += (s64)ntp_tick_adj << TICK_LENGTH_SHIFT;
-       second_length += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC);
+                               << NTP_SCALE_SHIFT;
+       second_length += (s64)ntp_tick_adj << NTP_SCALE_SHIFT;
+       second_length += time_freq;
 
        tick_length_base = second_length;
 
-       do_div(second_length, HZ);
-       tick_nsec = second_length >> TICK_LENGTH_SHIFT;
+       tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
+       tick_length_base = div_u64(tick_length_base, NTP_INTERVAL_FREQ);
+}
+
+static void ntp_update_offset(long offset)
+{
+       long mtemp;
+       s64 freq_adj;
+
+       if (!(time_status & STA_PLL))
+               return;
 
-       do_div(tick_length_base, NTP_INTERVAL_FREQ);
+       if (!(time_status & STA_NANO))
+               offset *= NSEC_PER_USEC;
+
+       /*
+        * Scale the phase adjustment and
+        * clamp to the operating range.
+        */
+       offset = min(offset, MAXPHASE);
+       offset = max(offset, -MAXPHASE);
+
+       /*
+        * Select how the frequency is to be controlled
+        * and in which mode (PLL or FLL).
+        */
+       if (time_status & STA_FREQHOLD || time_reftime == 0)
+               time_reftime = xtime.tv_sec;
+       mtemp = xtime.tv_sec - time_reftime;
+       time_reftime = xtime.tv_sec;
+
+       freq_adj = (s64)offset * mtemp;
+       freq_adj <<= NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant);
+       time_status &= ~STA_MODE;
+       if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
+               freq_adj += div_s64((s64)offset << (NTP_SCALE_SHIFT - SHIFT_FLL),
+                                   mtemp);
+               time_status |= STA_MODE;
+       }
+       freq_adj += time_freq;
+       freq_adj = min(freq_adj, MAXFREQ_SCALED);
+       time_freq = max(freq_adj, -MAXFREQ_SCALED);
+
+       time_offset = div_s64((s64)offset << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
 }
 
 /**
@@ -78,62 +123,70 @@ void ntp_clear(void)
 }
 
 /*
- * this routine handles the overflow of the microsecond field
- *
- * The tricky bits of code to handle the accurate clock support
- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
- * They were originally developed for SUN and DEC kernels.
- * All the kudos should go to Dave for this stuff.
+ * Leap second processing. If in leap-insert state at the end of the
+ * day, the system clock is set back one second; if in leap-delete
+ * state, the system clock is set ahead one second.
  */
-void second_overflow(void)
+static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
 {
-       long time_adj;
+       enum hrtimer_restart res = HRTIMER_NORESTART;
 
-       /* Bump the maxerror field */
-       time_maxerror += MAXFREQ >> SHIFT_USEC;
-       if (time_maxerror > NTP_PHASE_LIMIT) {
-               time_maxerror = NTP_PHASE_LIMIT;
-               time_status |= STA_UNSYNC;
-       }
+       write_seqlock_irq(&xtime_lock);
 
-       /*
-        * Leap second processing. If in leap-insert state at the end of the
-        * day, the system clock is set back one second; if in leap-delete
-        * state, the system clock is set ahead one second. The microtime()
-        * routine or external clock driver will insure that reported time is
-        * always monotonic. The ugly divides should be replaced.
-        */
        switch (time_state) {
        case TIME_OK:
-               if (time_status & STA_INS)
-                       time_state = TIME_INS;
-               else if (time_status & STA_DEL)
-                       time_state = TIME_DEL;
                break;
        case TIME_INS:
-               if (xtime.tv_sec % 86400 == 0) {
-                       xtime.tv_sec--;
-                       wall_to_monotonic.tv_sec++;
-                       time_state = TIME_OOP;
-                       printk(KERN_NOTICE "Clock: inserting leap second "
-                                       "23:59:60 UTC\n");
-               }
+               xtime.tv_sec--;
+               wall_to_monotonic.tv_sec++;
+               time_state = TIME_OOP;
+               printk(KERN_NOTICE "Clock: "
+                      "inserting leap second 23:59:60 UTC\n");
+               leap_timer.expires = ktime_add_ns(leap_timer.expires,
+                                                 NSEC_PER_SEC);
+               res = HRTIMER_RESTART;
                break;
        case TIME_DEL:
-               if ((xtime.tv_sec + 1) % 86400 == 0) {
-                       xtime.tv_sec++;
-                       wall_to_monotonic.tv_sec--;
-                       time_state = TIME_WAIT;
-                       printk(KERN_NOTICE "Clock: deleting leap second "
-                                       "23:59:59 UTC\n");
-               }
+               xtime.tv_sec++;
+               time_tai--;
+               wall_to_monotonic.tv_sec--;
+               time_state = TIME_WAIT;
+               printk(KERN_NOTICE "Clock: "
+                      "deleting leap second 23:59:59 UTC\n");
                break;
        case TIME_OOP:
+               time_tai++;
                time_state = TIME_WAIT;
-               break;
+               /* fall through */
        case TIME_WAIT:
                if (!(time_status & (STA_INS | STA_DEL)))
-               time_state = TIME_OK;
+                       time_state = TIME_OK;
+               break;
+       }
+       update_vsyscall(&xtime, clock);
+
+       write_sequnlock_irq(&xtime_lock);
+
+       return res;
+}
+
+/*
+ * this routine handles the overflow of the microsecond field
+ *
+ * The tricky bits of code to handle the accurate clock support
+ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
+ * They were originally developed for SUN and DEC kernels.
+ * All the kudos should go to Dave for this stuff.
+ */
+void second_overflow(void)
+{
+       s64 time_adj;
+
+       /* Bump the maxerror field */
+       time_maxerror += MAXFREQ / NSEC_PER_USEC;
+       if (time_maxerror > NTP_PHASE_LIMIT) {
+               time_maxerror = NTP_PHASE_LIMIT;
+               time_status |= STA_UNSYNC;
        }
 
        /*
@@ -143,7 +196,7 @@ void second_overflow(void)
        tick_length = tick_length_base;
        time_adj = shift_right(time_offset, SHIFT_PLL + time_constant);
        time_offset -= time_adj;
-       tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);
+       tick_length += time_adj;
 
        if (unlikely(time_adjust)) {
                if (time_adjust > MAX_TICKADJ) {
@@ -154,25 +207,12 @@ void second_overflow(void)
                        tick_length -= MAX_TICKADJ_SCALED;
                } else {
                        tick_length += (s64)(time_adjust * NSEC_PER_USEC /
-                                       NTP_INTERVAL_FREQ) << TICK_LENGTH_SHIFT;
+                                       NTP_INTERVAL_FREQ) << NTP_SCALE_SHIFT;
                        time_adjust = 0;
                }
        }
 }
 
-/*
- * Return how long ticks are at the moment, that is, how much time
- * update_wall_time_one_tick will add to xtime next time we call it
- * (assuming no calls to do_adjtimex in the meantime).
- * The return value is in fixed-point nanoseconds shifted by the
- * specified number of bits to the right of the binary point.
- * This function has no side-effects.
- */
-u64 current_tick_length(void)
-{
-       return tick_length;
-}
-
 #ifdef CONFIG_GENERIC_CMOS_UPDATE
 
 /* Disable the cmos update - used by virtualization and embedded */
@@ -236,8 +276,8 @@ static inline void notify_cmos_timer(void) { }
  */
 int do_adjtimex(struct timex *txc)
 {
-       long mtemp, save_adjust, rem;
-       s64 freq_adj, temp64;
+       struct timespec ts;
+       long save_adjust, sec;
        int result;
 
        /* In order to modify anything, you gotta be super-user! */
@@ -247,147 +287,132 @@ int do_adjtimex(struct timex *txc)
        /* Now we validate the data before disabling interrupts */
 
        if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) {
-         /* singleshot must not be used with any other mode bits */
-               if (txc->modes != ADJ_OFFSET_SINGLESHOT &&
-                                       txc->modes != ADJ_OFFSET_SS_READ)
+               /* singleshot must not be used with any other mode bits */
+               if (txc->modes & ~ADJ_OFFSET_SS_READ)
                        return -EINVAL;
        }
 
-       if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
-         /* adjustment Offset limited to +- .512 seconds */
-               if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
-                       return -EINVAL;
-
        /* if the quartz is off by more than 10% something is VERY wrong ! */
        if (txc->modes & ADJ_TICK)
                if (txc->tick <  900000/USER_HZ ||
                    txc->tick > 1100000/USER_HZ)
                        return -EINVAL;
 
+       if (time_state != TIME_OK && txc->modes & ADJ_STATUS)
+               hrtimer_cancel(&leap_timer);
+       getnstimeofday(&ts);
+
        write_seqlock_irq(&xtime_lock);
-       result = time_state;    /* mostly `TIME_OK' */
 
        /* Save for later - semantics of adjtime is to return old value */
        save_adjust = time_adjust;
 
-#if 0  /* STA_CLOCKERR is never set yet */
-       time_status &= ~STA_CLOCKERR;           /* reset STA_CLOCKERR */
-#endif
        /* If there are input parameters, then process them */
-       if (txc->modes)
-       {
-           if (txc->modes & ADJ_STATUS)        /* only set allowed bits */
-               time_status =  (txc->status & ~STA_RONLY) |
-                             (time_status & STA_RONLY);
-
-           if (txc->modes & ADJ_FREQUENCY) {   /* p. 22 */
-               if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
-                   result = -EINVAL;
-                   goto leave;
-               }
-               time_freq = ((s64)txc->freq * NSEC_PER_USEC)
-                               >> (SHIFT_USEC - SHIFT_NSEC);
-           }
-
-           if (txc->modes & ADJ_MAXERROR) {
-               if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
-                   result = -EINVAL;
-                   goto leave;
+       if (txc->modes) {
+               if (txc->modes & ADJ_STATUS) {
+                       if ((time_status & STA_PLL) &&
+                           !(txc->status & STA_PLL)) {
+                               time_state = TIME_OK;
+                               time_status = STA_UNSYNC;
+                       }
+                       /* only set allowed bits */
+                       time_status &= STA_RONLY;
+                       time_status |= txc->status & ~STA_RONLY;
+
+                       switch (time_state) {
+                       case TIME_OK:
+                       start_timer:
+                               sec = ts.tv_sec;
+                               if (time_status & STA_INS) {
+                                       time_state = TIME_INS;
+                                       sec += 86400 - sec % 86400;
+                                       hrtimer_start(&leap_timer, ktime_set(sec, 0), HRTIMER_MODE_ABS);
+                               } else if (time_status & STA_DEL) {
+                                       time_state = TIME_DEL;
+                                       sec += 86400 - (sec + 1) % 86400;
+                                       hrtimer_start(&leap_timer, ktime_set(sec, 0), HRTIMER_MODE_ABS);
+                               }
+                               break;
+                       case TIME_INS:
+                       case TIME_DEL:
+                               time_state = TIME_OK;
+                               goto start_timer;
+                               break;
+                       case TIME_WAIT:
+                               if (!(time_status & (STA_INS | STA_DEL)))
+                                       time_state = TIME_OK;
+                               break;
+                       case TIME_OOP:
+                               hrtimer_restart(&leap_timer);
+                               break;
+                       }
                }
-               time_maxerror = txc->maxerror;
-           }
 
-           if (txc->modes & ADJ_ESTERROR) {
-               if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
-                   result = -EINVAL;
-                   goto leave;
+               if (txc->modes & ADJ_NANO)
+                       time_status |= STA_NANO;
+               if (txc->modes & ADJ_MICRO)
+                       time_status &= ~STA_NANO;
+
+               if (txc->modes & ADJ_FREQUENCY) {
+                       time_freq = (s64)txc->freq * PPM_SCALE;
+                       time_freq = min(time_freq, MAXFREQ_SCALED);
+                       time_freq = max(time_freq, -MAXFREQ_SCALED);
                }
-               time_esterror = txc->esterror;
-           }
 
-           if (txc->modes & ADJ_TIMECONST) {   /* p. 24 */
-               if (txc->constant < 0) {        /* NTP v4 uses values > 6 */
-                   result = -EINVAL;
-                   goto leave;
+               if (txc->modes & ADJ_MAXERROR)
+                       time_maxerror = txc->maxerror;
+               if (txc->modes & ADJ_ESTERROR)
+                       time_esterror = txc->esterror;
+
+               if (txc->modes & ADJ_TIMECONST) {
+                       time_constant = txc->constant;
+                       if (!(time_status & STA_NANO))
+                               time_constant += 4;
+                       time_constant = min(time_constant, (long)MAXTC);
+                       time_constant = max(time_constant, 0l);
                }
-               time_constant = min(txc->constant + 4, (long)MAXTC);
-           }
 
-           if (txc->modes & ADJ_OFFSET) {      /* values checked earlier */
-               if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
-                   /* adjtime() is independent from ntp_adjtime() */
-                   time_adjust = txc->offset;
+               if (txc->modes & ADJ_TAI && txc->constant > 0)
+                       time_tai = txc->constant;
+
+               if (txc->modes & ADJ_OFFSET) {
+                       if (txc->modes == ADJ_OFFSET_SINGLESHOT)
+                               /* adjtime() is independent from ntp_adjtime() */
+                               time_adjust = txc->offset;
+                       else
+                               ntp_update_offset(txc->offset);
                }
-               else if (time_status & STA_PLL) {
-                   time_offset = txc->offset * NSEC_PER_USEC;
-
-                   /*
-                    * Scale the phase adjustment and
-                    * clamp to the operating range.
-                    */
-                   time_offset = min(time_offset, (s64)MAXPHASE * NSEC_PER_USEC);
-                   time_offset = max(time_offset, (s64)-MAXPHASE * NSEC_PER_USEC);
-
-                   /*
-                    * Select whether the frequency is to be controlled
-                    * and in which mode (PLL or FLL). Clamp to the operating
-                    * range. Ugly multiply/divide should be replaced someday.
-                    */
-
-                   if (time_status & STA_FREQHOLD || time_reftime == 0)
-                       time_reftime = xtime.tv_sec;
-                   mtemp = xtime.tv_sec - time_reftime;
-                   time_reftime = xtime.tv_sec;
-
-                   freq_adj = time_offset * mtemp;
-                   freq_adj = shift_right(freq_adj, time_constant * 2 +
-                                          (SHIFT_PLL + 2) * 2 - SHIFT_NSEC);
-                   if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
-                       u64 utemp64;
-                       temp64 = time_offset << (SHIFT_NSEC - SHIFT_FLL);
-                       if (time_offset < 0) {
-                           utemp64 = -temp64;
-                           do_div(utemp64, mtemp);
-                           freq_adj -= utemp64;
-                       } else {
-                           utemp64 = temp64;
-                           do_div(utemp64, mtemp);
-                           freq_adj += utemp64;
-                       }
-                   }
-                   freq_adj += time_freq;
-                   freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);
-                   time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC);
-                   time_offset = div_long_long_rem_signed(time_offset,
-                                                          NTP_INTERVAL_FREQ,
-                                                          &rem);
-                   time_offset <<= SHIFT_UPDATE;
-               } /* STA_PLL */
-           } /* txc->modes & ADJ_OFFSET */
-           if (txc->modes & ADJ_TICK)
-               tick_usec = txc->tick;
-
-           if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
-                   ntp_update_frequency();
-       } /* txc->modes */
-leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
+               if (txc->modes & ADJ_TICK)
+                       tick_usec = txc->tick;
+
+               if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
+                       ntp_update_frequency();
+       }
+
+       result = time_state;    /* mostly `TIME_OK' */
+       if (time_status & (STA_UNSYNC|STA_CLOCKERR))
                result = TIME_ERROR;
 
        if ((txc->modes == ADJ_OFFSET_SINGLESHOT) ||
-                       (txc->modes == ADJ_OFFSET_SS_READ))
+           (txc->modes == ADJ_OFFSET_SS_READ))
                txc->offset = save_adjust;
-       else
-               txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) *
-                               NTP_INTERVAL_FREQ / 1000;
-       txc->freq          = (time_freq / NSEC_PER_USEC) <<
-                               (SHIFT_USEC - SHIFT_NSEC);
+       else {
+               txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
+                                         NTP_SCALE_SHIFT);
+               if (!(time_status & STA_NANO))
+                       txc->offset /= NSEC_PER_USEC;
+       }
+       txc->freq          = shift_right((s32)(time_freq >> PPM_SCALE_INV_SHIFT) *
+                                        (s64)PPM_SCALE_INV,
+                                        NTP_SCALE_SHIFT);
        txc->maxerror      = time_maxerror;
        txc->esterror      = time_esterror;
        txc->status        = time_status;
        txc->constant      = time_constant;
        txc->precision     = 1;
-       txc->tolerance     = MAXFREQ;
+       txc->tolerance     = MAXFREQ_SCALED / PPM_SCALE;
        txc->tick          = tick_usec;
+       txc->tai           = time_tai;
 
        /* PPS is not implemented, so these are zero */
        txc->ppsfreq       = 0;
@@ -399,9 +424,15 @@ leave:     if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
        txc->errcnt        = 0;
        txc->stbcnt        = 0;
        write_sequnlock_irq(&xtime_lock);
-       do_gettimeofday(&txc->time);
+
+       txc->time.tv_sec = ts.tv_sec;
+       txc->time.tv_usec = ts.tv_nsec;
+       if (!(time_status & STA_NANO))
+               txc->time.tv_usec /= NSEC_PER_USEC;
+
        notify_cmos_timer();
-       return(result);
+
+       return result;
 }
 
 static int __init ntp_tick_adj_setup(char *str)
@@ -411,3 +442,10 @@ static int __init ntp_tick_adj_setup(char *str)
 }
 
 __setup("ntp_tick_adj=", ntp_tick_adj_setup);
+
+void __init ntp_init(void)
+{
+       ntp_clear();
+       hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+       leap_timer.function = ntp_leap_second;
+}
index 2d6087c7cf9820fb4a16c43fdd75ed9f33d16bca..e91c29f961c900d7739c0dc2f27b81c480cdb55c 100644 (file)
@@ -53,7 +53,7 @@ void update_xtime_cache(u64 nsec)
        timespec_add_ns(&xtime_cache, nsec);
 }
 
-static struct clocksource *clock; /* pointer to current clocksource */
+struct clocksource *clock;
 
 
 #ifdef CONFIG_GENERIC_TIME
@@ -246,7 +246,7 @@ void __init timekeeping_init(void)
 
        write_seqlock_irqsave(&xtime_lock, flags);
 
-       ntp_clear();
+       ntp_init();
 
        clock = clocksource_get_next();
        clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
@@ -371,7 +371,7 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
         * here.  This is tuned so that an error of about 1 msec is adjusted
         * within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
         */
-       error2 = clock->error >> (TICK_LENGTH_SHIFT + 22 - 2 * SHIFT_HZ);
+       error2 = clock->error >> (NTP_SCALE_SHIFT + 22 - 2 * SHIFT_HZ);
        error2 = abs(error2);
        for (look_ahead = 0; error2 > 0; look_ahead++)
                error2 >>= 2;
@@ -380,8 +380,7 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
         * Now calculate the error in (1 << look_ahead) ticks, but first
         * remove the single look ahead already included in the error.
         */
-       tick_error = current_tick_length() >>
-               (TICK_LENGTH_SHIFT - clock->shift + 1);
+       tick_error = tick_length >> (NTP_SCALE_SHIFT - clock->shift + 1);
        tick_error -= clock->xtime_interval >> 1;
        error = ((error - tick_error) >> look_ahead) + tick_error;
 
@@ -412,7 +411,7 @@ static void clocksource_adjust(s64 offset)
        s64 error, interval = clock->cycle_interval;
        int adj;
 
-       error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
+       error = clock->error >> (NTP_SCALE_SHIFT - clock->shift - 1);
        if (error > interval) {
                error >>= 2;
                if (likely(error <= interval))
@@ -434,7 +433,7 @@ static void clocksource_adjust(s64 offset)
        clock->xtime_interval += interval;
        clock->xtime_nsec -= offset;
        clock->error -= (interval - offset) <<
-                       (TICK_LENGTH_SHIFT - clock->shift);
+                       (NTP_SCALE_SHIFT - clock->shift);
 }
 
 /**
@@ -473,8 +472,8 @@ void update_wall_time(void)
                }
 
                /* accumulate error between NTP and clock interval */
-               clock->error += current_tick_length();
-               clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
+               clock->error += tick_length;
+               clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift);
        }
 
        /* correct the clock when NTP error is too big */
index 721093a22561100bd626a9e16981c768ead6c40f..29fc39f1029cec92528b0cb66380028670b9eee1 100644 (file)
@@ -195,7 +195,6 @@ static void delayed_work_timer_fn(unsigned long __data)
 int queue_delayed_work(struct workqueue_struct *wq,
                        struct delayed_work *dwork, unsigned long delay)
 {
-       timer_stats_timer_set_start_info(&dwork->timer);
        if (delay == 0)
                return queue_work(wq, &dwork->work);
 
@@ -219,11 +218,12 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
        struct timer_list *timer = &dwork->timer;
        struct work_struct *work = &dwork->work;
 
-       timer_stats_timer_set_start_info(&dwork->timer);
        if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
                BUG_ON(timer_pending(timer));
                BUG_ON(!list_empty(&work->entry));
 
+               timer_stats_timer_set_start_info(&dwork->timer);
+
                /* This stores cwq for the moment, for the timer_fn */
                set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
                timer->expires = jiffies + delay;
@@ -564,7 +564,6 @@ EXPORT_SYMBOL(schedule_work);
 int schedule_delayed_work(struct delayed_work *dwork,
                                        unsigned long delay)
 {
-       timer_stats_timer_set_start_info(&dwork->timer);
        return queue_delayed_work(keventd_wq, dwork, delay);
 }
 EXPORT_SYMBOL(schedule_delayed_work);
@@ -581,7 +580,6 @@ EXPORT_SYMBOL(schedule_delayed_work);
 int schedule_delayed_work_on(int cpu,
                        struct delayed_work *dwork, unsigned long delay)
 {
-       timer_stats_timer_set_start_info(&dwork->timer);
        return queue_delayed_work_on(cpu, keventd_wq, dwork, delay);
 }
 EXPORT_SYMBOL(schedule_delayed_work_on);
index edc27a5d1b735aba4855d33e9756ab375d9569ce..26c87c49d776cf8365e9ff7ba2a7319e481f716f 100644 (file)
@@ -20,7 +20,7 @@ static int devm_ioremap_match(struct device *dev, void *res, void *match_data)
  *
  * Managed ioremap().  Map is automatically unmapped on driver detach.
  */
-void __iomem *devm_ioremap(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
                           unsigned long size)
 {
        void __iomem **ptr, *addr;
@@ -49,7 +49,7 @@ EXPORT_SYMBOL(devm_ioremap);
  * Managed ioremap_nocache().  Map is automatically unmapped on driver
  * detach.
  */
-void __iomem *devm_ioremap_nocache(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
                                   unsigned long size)
 {
        void __iomem **ptr, *addr;
index b71cf93c529adaa3364afa4a1b997c54cc9ef363..bb5bd0c0f030a9cf44c57ef07b50fac3e7170ce8 100644 (file)
@@ -16,9 +16,8 @@
  * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
  */
 
-#include <linux/types.h>
 #include <linux/module.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
 
 /* Not needed on 64bit architectures */
 #if BITS_PER_LONG == 32
@@ -58,10 +57,31 @@ uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
 
 EXPORT_SYMBOL(__div64_32);
 
+#ifndef div_s64_rem
+s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+       u64 quotient;
+
+       if (dividend < 0) {
+               quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
+               *remainder = -*remainder;
+               if (divisor > 0)
+                       quotient = -quotient;
+       } else {
+               quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
+               if (divisor < 0)
+                       quotient = -quotient;
+       }
+       return quotient;
+}
+EXPORT_SYMBOL(div_s64_rem);
+#endif
+
 /* 64bit divisor, dividend and result. dynamic precision */
-uint64_t div64_64(uint64_t dividend, uint64_t divisor)
+#ifndef div64_u64
+u64 div64_u64(u64 dividend, u64 divisor)
 {
-       uint32_t high, d;
+       u32 high, d;
 
        high = divisor >> 32;
        if (high) {
@@ -72,10 +92,9 @@ uint64_t div64_64(uint64_t dividend, uint64_t divisor)
        } else
                d = divisor;
 
-       do_div(dividend, d);
-
-       return dividend;
+       return div_u64(dividend, d);
 }
-EXPORT_SYMBOL(div64_64);
+EXPORT_SYMBOL(div64_u64);
+#endif
 
 #endif /* BITS_PER_LONG == 32 */
index 8368c81fcb7d21cd3d85c8c0880f918b9c1911f5..7a02e173f02773c2bc5fc3bfa763e269ef1b9f7a 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -385,8 +385,8 @@ void idr_remove(struct idr *idp, int id)
        while (idp->id_free_cnt >= IDR_FREE_MAX) {
                p = alloc_layer(idp);
                kmem_cache_free(idr_layer_cache, p);
-               return;
        }
+       return;
 }
 EXPORT_SYMBOL(idr_remove);
 
index 120bd175aa7855044fdb5a440b6fc189b21344b3..cca37f96faa22b5cbe73de502da86cd94f61997f 100644 (file)
@@ -1,38 +1,37 @@
 /*
- *     klist.c - Routines for manipulating klists.
+ * klist.c - Routines for manipulating klists.
  *
+ * Copyright (C) 2005 Patrick Mochel
  *
- *     This klist interface provides a couple of structures that wrap around 
- *     struct list_head to provide explicit list "head" (struct klist) and 
- *     list "node" (struct klist_node) objects. For struct klist, a spinlock
- *     is included that protects access to the actual list itself. struct 
- *     klist_node provides a pointer to the klist that owns it and a kref
- *     reference count that indicates the number of current users of that node
- *     in the list.
+ * This file is released under the GPL v2.
  *
- *     The entire point is to provide an interface for iterating over a list
- *     that is safe and allows for modification of the list during the
- *     iteration (e.g. insertion and removal), including modification of the
- *     current node on the list.
+ * This klist interface provides a couple of structures that wrap around
+ * struct list_head to provide explicit list "head" (struct klist) and list
+ * "node" (struct klist_node) objects. For struct klist, a spinlock is
+ * included that protects access to the actual list itself. struct
+ * klist_node provides a pointer to the klist that owns it and a kref
+ * reference count that indicates the number of current users of that node
+ * in the list.
  *
- *     It works using a 3rd object type - struct klist_iter - that is declared
- *     and initialized before an iteration. klist_next() is used to acquire the
- *     next element in the list. It returns NULL if there are no more items.
- *     Internally, that routine takes the klist's lock, decrements the reference
- *     count of the previous klist_node and increments the count of the next
- *     klist_node. It then drops the lock and returns.
+ * The entire point is to provide an interface for iterating over a list
+ * that is safe and allows for modification of the list during the
+ * iteration (e.g. insertion and removal), including modification of the
+ * current node on the list.
  *
- *     There are primitives for adding and removing nodes to/from a klist. 
- *     When deleting, klist_del() will simply decrement the reference count. 
- *     Only when the count goes to 0 is the node removed from the list. 
- *     klist_remove() will try to delete the node from the list and block
- *     until it is actually removed. This is useful for objects (like devices)
- *     that have been removed from the system and must be freed (but must wait
- *     until all accessors have finished).
+ * It works using a 3rd object type - struct klist_iter - that is declared
+ * and initialized before an iteration. klist_next() is used to acquire the
+ * next element in the list. It returns NULL if there are no more items.
+ * Internally, that routine takes the klist's lock, decrements the
+ * reference count of the previous klist_node and increments the count of
+ * the next klist_node. It then drops the lock and returns.
  *
- *     Copyright (C) 2005 Patrick Mochel
- *
- *     This file is released under the GPL v2.
+ * There are primitives for adding and removing nodes to/from a klist.
+ * When deleting, klist_del() will simply decrement the reference count.
+ * Only when the count goes to 0 is the node removed from the list.
+ * klist_remove() will try to delete the node from the list and block until
+ * it is actually removed. This is useful for objects (like devices) that
+ * have been removed from the system and must be freed (but must wait until
+ * all accessors have finished).
  */
 
 #include <linux/klist.h>
 
 
 /**
- *     klist_init - Initialize a klist structure. 
- *     @k:     The klist we're initializing.
- *     @get:   The get function for the embedding object (NULL if none)
- *     @put:   The put function for the embedding object (NULL if none)
+ * klist_init - Initialize a klist structure.
+ * @k: The klist we're initializing.
+ * @get: The get function for the embedding object (NULL if none)
+ * @put: The put function for the embedding object (NULL if none)
  *
  * Initialises the klist structure.  If the klist_node structures are
  * going to be embedded in refcounted objects (necessary for safe
@@ -51,8 +50,7 @@
  * functions that take and release references on the embedding
  * objects.
  */
-
-void klist_init(struct klist * k, void (*get)(struct klist_node *),
+void klist_init(struct klist *k, void (*get)(struct klist_node *),
                void (*put)(struct klist_node *))
 {
        INIT_LIST_HEAD(&k->k_list);
@@ -60,26 +58,23 @@ void klist_init(struct klist * k, void (*get)(struct klist_node *),
        k->get = get;
        k->put = put;
 }
-
 EXPORT_SYMBOL_GPL(klist_init);
 
-
-static void add_head(struct klist * k, struct klist_node * n)
+static void add_head(struct klist *k, struct klist_node *n)
 {
        spin_lock(&k->k_lock);
        list_add(&n->n_node, &k->k_list);
        spin_unlock(&k->k_lock);
 }
 
-static void add_tail(struct klist * k, struct klist_node * n)
+static void add_tail(struct klist *k, struct klist_node *n)
 {
        spin_lock(&k->k_lock);
        list_add_tail(&n->n_node, &k->k_list);
        spin_unlock(&k->k_lock);
 }
 
-
-static void klist_node_init(struct klist * k, struct klist_node * n)
+static void klist_node_init(struct klist *k, struct klist_node *n)
 {
        INIT_LIST_HEAD(&n->n_node);
        init_completion(&n->n_removed);
@@ -89,60 +84,83 @@ static void klist_node_init(struct klist * k, struct klist_node * n)
                k->get(n);
 }
 
-
 /**
- *     klist_add_head - Initialize a klist_node and add it to front.
- *     @n:     node we're adding.
- *     @k:     klist it's going on.
+ * klist_add_head - Initialize a klist_node and add it to front.
+ * @n: node we're adding.
+ * @k: klist it's going on.
  */
-
-void klist_add_head(struct klist_node * n, struct klist * k)
+void klist_add_head(struct klist_node *n, struct klist *k)
 {
        klist_node_init(k, n);
        add_head(k, n);
 }
-
 EXPORT_SYMBOL_GPL(klist_add_head);
 
-
 /**
- *     klist_add_tail - Initialize a klist_node and add it to back.
- *     @n:     node we're adding.
- *     @k:     klist it's going on.
+ * klist_add_tail - Initialize a klist_node and add it to back.
+ * @n: node we're adding.
+ * @k: klist it's going on.
  */
-
-void klist_add_tail(struct klist_node * n, struct klist * k)
+void klist_add_tail(struct klist_node *n, struct klist *k)
 {
        klist_node_init(k, n);
        add_tail(k, n);
 }
-
 EXPORT_SYMBOL_GPL(klist_add_tail);
 
+/**
+ * klist_add_after - Init a klist_node and add it after an existing node
+ * @n: node we're adding.
+ * @pos: node to put @n after
+ */
+void klist_add_after(struct klist_node *n, struct klist_node *pos)
+{
+       struct klist *k = pos->n_klist;
+
+       klist_node_init(k, n);
+       spin_lock(&k->k_lock);
+       list_add(&n->n_node, &pos->n_node);
+       spin_unlock(&k->k_lock);
+}
+EXPORT_SYMBOL_GPL(klist_add_after);
+
+/**
+ * klist_add_before - Init a klist_node and add it before an existing node
+ * @n: node we're adding.
+ * @pos: node to put @n after
+ */
+void klist_add_before(struct klist_node *n, struct klist_node *pos)
+{
+       struct klist *k = pos->n_klist;
+
+       klist_node_init(k, n);
+       spin_lock(&k->k_lock);
+       list_add_tail(&n->n_node, &pos->n_node);
+       spin_unlock(&k->k_lock);
+}
+EXPORT_SYMBOL_GPL(klist_add_before);
 
-static void klist_release(struct kref * kref)
+static void klist_release(struct kref *kref)
 {
-       struct klist_node * n = container_of(kref, struct klist_node, n_ref);
+       struct klist_node *n = container_of(kref, struct klist_node, n_ref);
 
        list_del(&n->n_node);
        complete(&n->n_removed);
        n->n_klist = NULL;
 }
 
-static int klist_dec_and_del(struct klist_node * n)
+static int klist_dec_and_del(struct klist_node *n)
 {
        return kref_put(&n->n_ref, klist_release);
 }
 
-
 /**
- *     klist_del - Decrement the reference count of node and try to remove.
- *     @n:     node we're deleting.
+ * klist_del - Decrement the reference count of node and try to remove.
+ * @n: node we're deleting.
  */
-
-void klist_del(struct klist_node * n)
+void klist_del(struct klist_node *n)
 {
-       struct klist * k = n->n_klist;
+       struct klist *k = n->n_klist;
        void (*put)(struct klist_node *) = k->put;
 
        spin_lock(&k->k_lock);
@@ -152,48 +170,40 @@ void klist_del(struct klist_node * n)
        if (put)
                put(n);
 }
-
 EXPORT_SYMBOL_GPL(klist_del);
 
-
 /**
- *     klist_remove - Decrement the refcount of node and wait for it to go away.
- *     @n:     node we're removing.
+ * klist_remove - Decrement the refcount of node and wait for it to go away.
+ * @n: node we're removing.
  */
-
-void klist_remove(struct klist_node * n)
+void klist_remove(struct klist_node *n)
 {
        klist_del(n);
        wait_for_completion(&n->n_removed);
 }
-
 EXPORT_SYMBOL_GPL(klist_remove);
 
-
 /**
- *     klist_node_attached - Say whether a node is bound to a list or not.
- *     @n:     Node that we're testing.
+ * klist_node_attached - Say whether a node is bound to a list or not.
+ * @n: Node that we're testing.
  */
-
-int klist_node_attached(struct klist_node * n)
+int klist_node_attached(struct klist_node *n)
 {
        return (n->n_klist != NULL);
 }
-
 EXPORT_SYMBOL_GPL(klist_node_attached);
 
-
 /**
- *     klist_iter_init_node - Initialize a klist_iter structure.
- *     @k:     klist we're iterating.
- *     @i:     klist_iter we're filling.
- *     @n:     node to start with.
+ * klist_iter_init_node - Initialize a klist_iter structure.
+ * @k: klist we're iterating.
+ * @i: klist_iter we're filling.
+ * @n: node to start with.
  *
- *     Similar to klist_iter_init(), but starts the action off with @n, 
- *     instead of with the list head.
+ * Similar to klist_iter_init(), but starts the action off with @n,
+ * instead of with the list head.
  */
-
-void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
+void klist_iter_init_node(struct klist *k, struct klist_iter *i,
+                         struct klist_node *n)
 {
        i->i_klist = k;
        i->i_head = &k->k_list;
@@ -201,66 +211,56 @@ void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_
        if (n)
                kref_get(&n->n_ref);
 }
-
 EXPORT_SYMBOL_GPL(klist_iter_init_node);
 
-
 /**
- *     klist_iter_init - Iniitalize a klist_iter structure.
- *     @k:     klist we're iterating.
- *     @i:     klist_iter structure we're filling.
+ * klist_iter_init - Iniitalize a klist_iter structure.
+ * @k: klist we're iterating.
+ * @i: klist_iter structure we're filling.
  *
- *     Similar to klist_iter_init_node(), but start with the list head.
+ * Similar to klist_iter_init_node(), but start with the list head.
  */
-
-void klist_iter_init(struct klist * k, struct klist_iter * i)
+void klist_iter_init(struct klist *k, struct klist_iter *i)
 {
        klist_iter_init_node(k, i, NULL);
 }
-
 EXPORT_SYMBOL_GPL(klist_iter_init);
 
-
 /**
- *     klist_iter_exit - Finish a list iteration.
- *     @i:     Iterator structure.
+ * klist_iter_exit - Finish a list iteration.
+ * @i: Iterator structure.
  *
- *     Must be called when done iterating over list, as it decrements the 
- *     refcount of the current node. Necessary in case iteration exited before
- *     the end of the list was reached, and always good form.
+ * Must be called when done iterating over list, as it decrements the
+ * refcount of the current node. Necessary in case iteration exited before
+ * the end of the list was reached, and always good form.
  */
-
-void klist_iter_exit(struct klist_iter * i)
+void klist_iter_exit(struct klist_iter *i)
 {
        if (i->i_cur) {
                klist_del(i->i_cur);
                i->i_cur = NULL;
        }
 }
-
 EXPORT_SYMBOL_GPL(klist_iter_exit);
 
-
-static struct klist_node * to_klist_node(struct list_head * n)
+static struct klist_node *to_klist_node(struct list_head *n)
 {
        return container_of(n, struct klist_node, n_node);
 }
 
-
 /**
- *     klist_next - Ante up next node in list.
- *     @i:     Iterator structure.
+ * klist_next - Ante up next node in list.
+ * @i: Iterator structure.
  *
- *     First grab list lock. Decrement the reference count of the previous
- *     node, if there was one. Grab the next node, increment its reference 
- *     count, drop the lock, and return that next node.
+ * First grab list lock. Decrement the reference count of the previous
+ * node, if there was one. Grab the next node, increment its reference
+ * count, drop the lock, and return that next node.
  */
-
-struct klist_node * klist_next(struct klist_iter * i)
+struct klist_node *klist_next(struct klist_iter *i)
 {
-       struct list_head * next;
-       struct klist_node * lnode = i->i_cur;
-       struct klist_node * knode = NULL;
+       struct list_head *next;
+       struct klist_node *lnode = i->i_cur;
+       struct klist_node *knode = NULL;
        void (*put)(struct klist_node *) = i->i_klist->put;
 
        spin_lock(&i->i_klist->k_lock);
@@ -281,7 +281,4 @@ struct klist_node * klist_next(struct klist_iter * i)
                put(lnode);
        return knode;
 }
-
 EXPORT_SYMBOL_GPL(klist_next);
-
-
index fd78740321639afdf10438ed1890a5a61be15c18..718e5101c263596224f7f35b523cea27e093ecd6 100644 (file)
@@ -216,21 +216,12 @@ static int kobject_add_internal(struct kobject *kobj)
 static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                                  va_list vargs)
 {
-       va_list aq;
-       char *name;
-
-       va_copy(aq, vargs);
-       name = kvasprintf(GFP_KERNEL, fmt, vargs);
-       va_end(aq);
-
-       if (!name)
-               return -ENOMEM;
-
        /* Free the old name, if necessary. */
        kfree(kobj->name);
 
-       /* Now, set the new name */
-       kobj->name = name;
+       kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+       if (!kobj->name)
+               return -ENOMEM;
 
        return 0;
 }
@@ -246,12 +237,12 @@ static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
  */
 int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
 {
-       va_list args;
+       va_list vargs;
        int retval;
 
-       va_start(args, fmt);
-       retval = kobject_set_name_vargs(kobj, fmt, args);
-       va_end(args);
+       va_start(vargs, fmt);
+       retval = kobject_set_name_vargs(kobj, fmt, vargs);
+       va_end(vargs);
 
        return retval;
 }
@@ -301,12 +292,9 @@ EXPORT_SYMBOL(kobject_init);
 static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
                            const char *fmt, va_list vargs)
 {
-       va_list aq;
        int retval;
 
-       va_copy(aq, vargs);
-       retval = kobject_set_name_vargs(kobj, fmt, aq);
-       va_end(aq);
+       retval = kobject_set_name_vargs(kobj, fmt, vargs);
        if (retval) {
                printk(KERN_ERR "kobject: can not set name properly!\n");
                return retval;
index 5efafed3d6b65df9e56f968e32fb012f4cd13c65..b19b87af65a3553a0650d679cabfac9fecd4eb3b 100644 (file)
@@ -493,6 +493,33 @@ char *strsep(char **s, const char *ct)
 EXPORT_SYMBOL(strsep);
 #endif
 
+/**
+ * sysfs_streq - return true if strings are equal, modulo trailing newline
+ * @s1: one string
+ * @s2: another string
+ *
+ * This routine returns true iff two strings are equal, treating both
+ * NUL and newline-then-NUL as equivalent string terminations.  It's
+ * geared for use with sysfs input strings, which generally terminate
+ * with newlines but are compared against values without newlines.
+ */
+bool sysfs_streq(const char *s1, const char *s2)
+{
+       while (*s1 && *s1 == *s2) {
+               s1++;
+               s2++;
+       }
+
+       if (*s1 == *s2)
+               return true;
+       if (!*s1 && *s2 == '\n' && !s2[1])
+               return true;
+       if (*s1 == '\n' && !s1[1] && !*s2)
+               return true;
+       return false;
+}
+EXPORT_SYMBOL(sysfs_streq);
+
 #ifndef __HAVE_ARCH_MEMSET
 /**
  * memset - Fill a region of memory with the given value
index 33add96cd5fbf98c2f804fb2511aeec3f5a2594d..e46451e1d9b793563b08d8ef015927b484b0be1d 100644 (file)
@@ -48,6 +48,8 @@ enum mem_cgroup_stat_index {
         */
        MEM_CGROUP_STAT_CACHE,     /* # of pages charged as cache */
        MEM_CGROUP_STAT_RSS,       /* # of pages charged as rss */
+       MEM_CGROUP_STAT_PGPGIN_COUNT,   /* # of pages paged in */
+       MEM_CGROUP_STAT_PGPGOUT_COUNT,  /* # of pages paged out */
 
        MEM_CGROUP_STAT_NSTATS,
 };
@@ -199,6 +201,13 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *mem, int flags,
                __mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_CACHE, val);
        else
                __mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_RSS, val);
+
+       if (charge)
+               __mem_cgroup_stat_add_safe(stat,
+                               MEM_CGROUP_STAT_PGPGIN_COUNT, 1);
+       else
+               __mem_cgroup_stat_add_safe(stat,
+                               MEM_CGROUP_STAT_PGPGOUT_COUNT, 1);
 }
 
 static struct mem_cgroup_per_zone *
@@ -884,6 +893,8 @@ static const struct mem_cgroup_stat_desc {
 } mem_cgroup_stat_desc[] = {
        [MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
        [MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, },
+       [MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
+       [MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, },
 };
 
 static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
index 70db2897c1ea626ea3b6f576fda91fa6c3c48cd9..32b62623846af6a7242c11f641774adeff09d45b 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -22,6 +22,7 @@
 #include <linux/debugobjects.h>
 #include <linux/kallsyms.h>
 #include <linux/memory.h>
+#include <linux/math64.h>
 
 /*
  * Lock order:
@@ -3621,12 +3622,10 @@ static int list_locations(struct kmem_cache *s, char *buf,
                        len += sprintf(buf + len, "<not-available>");
 
                if (l->sum_time != l->min_time) {
-                       unsigned long remainder;
-
                        len += sprintf(buf + len, " age=%ld/%ld/%ld",
-                       l->min_time,
-                       div_long_long_rem(l->sum_time, l->count, &remainder),
-                       l->max_time);
+                               l->min_time,
+                               (long)div_u64(l->sum_time, l->count),
+                               l->max_time);
                } else
                        len += sprintf(buf + len, " age=%ld",
                                l->min_time);
index 2a39cf128aba2a7a583501a6686d9214070eb7bd..6e45b0f3d1256e0bdc3a3caffa74597cf96a5138 100644 (file)
@@ -547,6 +547,7 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
  *     @gfp_mask:      flags for the page level allocator
  *     @prot:          protection mask for the allocated pages
  *     @node:          node to use for allocation or -1
+ *     @caller:        caller's return address
  *
  *     Allocate enough pages to cover @size from the page level
  *     allocator with @gfp_mask flags.  Map them into contiguous
index eb5b9854c8c7330791ada69b8c9e8695f7a73f3d..4a1221e5e8ee2ec8b7d1a5157aa063f6a3f8011e 100644 (file)
@@ -15,8 +15,8 @@
 
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/math64.h>
 #include <net/tcp.h>
-#include <asm/div64.h>
 
 #define BICTCP_BETA_SCALE    1024      /* Scale factor beta calculation
                                         * max_cwnd = snd_cwnd * beta
@@ -128,7 +128,7 @@ static u32 cubic_root(u64 a)
         * x    = ( 2 * x  +  a / x  ) / 3
         *  k+1          k         k
         */
-       x = (2 * x + (u32)div64_64(a, (u64)x * (u64)(x - 1)));
+       x = (2 * x + (u32)div64_u64(a, (u64)x * (u64)(x - 1)));
        x = ((x * 341) >> 10);
        return x;
 }
index b4a26f2505f8864fab1943a282051d126dbebf4c..56d55fecf8ec49d49a79e804b0129e8570441df5 100644 (file)
@@ -1089,10 +1089,6 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
        if(level != SOL_IPV6)
                return -ENOPROTOOPT;
 
-       if (optname == MCAST_MSFILTER)
-               return compat_mc_getsockopt(sk, level, optname, optval, optlen,
-                       ipv6_getsockopt);
-
        err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
@@ -1131,6 +1127,10 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
        if (level != SOL_IPV6)
                return -ENOPROTOOPT;
 
+       if (optname == MCAST_MSFILTER)
+               return compat_mc_getsockopt(sk, level, optname, optval, optlen,
+                       ipv6_getsockopt);
+
        err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
index b15e7e2fa14328612cdf4de25150cc62604e8a58..d7e8983cd37f6303921edf25bc201eca7e99c4a2 100644 (file)
@@ -4,12 +4,11 @@
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/skbuff.h>
+#include <linux/math64.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_connbytes.h>
 #include <net/netfilter/nf_conntrack.h>
 
-#include <asm/div64.h>
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
@@ -82,7 +81,7 @@ connbytes_mt(const struct sk_buff *skb, const struct net_device *in,
                        break;
                }
                if (pkts != 0)
-                       what = div64_64(bytes, pkts);
+                       what = div64_u64(bytes, pkts);
                break;
        }
 
index 62e1e02126e61d5cde4945c9d7f922153ea6f90e..5552154cbedb723411708a2723f1a4f07a30890f 100644 (file)
@@ -36,8 +36,10 @@ trap "rm -f $tmp" 0 1 2 3 15
 
 # Check if we can link to ncurses
 check() {
-       echo -e " #include CURSES_LOC \n main() {}" |
-           $cc -xc - -o $tmp 2> /dev/null
+        $cc -xc - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
        if [ $? != 0 ]; then
            echo " *** Unable to find the ncurses libraries or the"       1>&2
            echo " *** required header files."                            1>&2
index 1b50a6ebc55fca85edaa9b7ef6256f31cc07ad4d..1c864c0efe2b90592d0e86a49e7347ff8ad02829 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/spinlock.h>
 #include <linux/syscalls.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/ext2_fs.h>
index c82cf15730a1e85c751483f75944e8905c0baa10..e89338e2b04379d7c29e816de44e8b6824b7885e 100644 (file)
@@ -834,16 +834,9 @@ static const struct file_operations kvm_vcpu_fops = {
  */
 static int create_vcpu_fd(struct kvm_vcpu *vcpu)
 {
-       int fd, r;
-       struct inode *inode;
-       struct file *file;
-
-       r = anon_inode_getfd(&fd, &inode, &file,
-                            "kvm-vcpu", &kvm_vcpu_fops, vcpu);
-       if (r) {
+       int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu);
+       if (fd < 0)
                kvm_put_kvm(vcpu->kvm);
-               return r;
-       }
        return fd;
 }
 
@@ -1168,19 +1161,15 @@ static const struct file_operations kvm_vm_fops = {
 
 static int kvm_dev_ioctl_create_vm(void)
 {
-       int fd, r;
-       struct inode *inode;
-       struct file *file;
+       int fd;
        struct kvm *kvm;
 
        kvm = kvm_create_vm();
        if (IS_ERR(kvm))
                return PTR_ERR(kvm);
-       r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
-       if (r) {
+       fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm);
+       if (fd < 0)
                kvm_put_kvm(kvm);
-               return r;
-       }
 
        return fd;
 }