Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 18:17:04 +0000 (11:17 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 18:17:04 +0000 (11:17 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (61 commits)
  Dynamic debug: fix pr_fmt() build error
  Dynamic debug: allow simple quoting of words
  dynamic debug: update docs
  dynamic debug: combine dprintk and dynamic printk
  sysfs: fix some bin_vm_ops errors
  kobject: don't block for each kobject_uevent
  sysfs: only allow one scheduled removal callback per kobj
  Driver core: Fix device_move() vs. dpm list ordering, v2
  Driver core: some cleanup on drivers/base/sys.c
  Driver core: implement uevent suppress in kobject
  vcs: hook sysfs devices into object lifetime instead of "binding"
  driver core: fix passing platform_data
  driver core: move platform_data into platform_device
  sysfs: don't block indefinitely for unmapped files.
  driver core: move knode_bus into private structure
  driver core: move knode_driver into private structure
  driver core: move klist_children into private structure
  driver core: create a private portion of struct device
  driver core: remove polling for driver_probe_done(v5)
  sysfs: reference sysfs_dirent from sysfs inodes
  ...

Fixed conflicts in drivers/sh/maple/maple.c manually

1  2 
Documentation/kernel-parameters.txt
drivers/sh/maple/maple.c
drivers/video/sh_mobile_lcdcfb.c
lib/Makefile

index 224263e7711f78d98fcc0becec0a92db2aac6f38,3a1aa8a4affcfc9756b60c9f30d63ea9b73c26b9..1a29ff3df3c58231a3c8a639758a9f9e7557ea6b
@@@ -44,7 -44,6 +44,7 @@@ parameter is applicable
        FB      The frame buffer device is enabled.
        HW      Appropriate hardware is enabled.
        IA-64   IA-64 architecture is enabled.
 +      IMA     Integrity measurement architecture is enabled.
        IOSCHED More than one I/O scheduler is enabled.
        IP_PNP  IP DHCP, BOOTP, or RARP is enabled.
        ISAPNP  ISA PnP code is enabled.
@@@ -903,15 -902,6 +903,15 @@@ and is between 256 and 4096 characters
        ihash_entries=  [KNL]
                        Set number of hash buckets for inode cache.
  
 +      ima_audit=      [IMA]
 +                      Format: { "0" | "1" }
 +                      0 -- integrity auditing messages. (Default)
 +                      1 -- enable informational integrity auditing messages.
 +
 +      ima_hash=       [IMA]
 +                      Formt: { "sha1" | "md5" }
 +                      default: "sha1"
 +
        in2000=         [HW,SCSI]
                        See header of drivers/scsi/in2000.c.
  
                        autoconfiguration.
                        Ranges are in pairs (memory base and size).
  
-       dynamic_printk  Enables pr_debug()/dev_dbg() calls if
-                       CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled.
-                       These can also be switched on/off via
-                       <debugfs>/dynamic_printk/modules
        print-fatal-signals=
                        [KNL] debug: print fatal signals
                        print-fatal-signals=1: print segfault info to
diff --combined drivers/sh/maple/maple.c
index c71bb4b4ce8476efbaa0e70bca1fccc3ab2666b5,7e1257af3d41f70e03795153a4dd672d087c42a8..cab1ab7cfb789204f70924975fc78b94bafe802a
@@@ -1,10 -1,16 +1,10 @@@
  /*
   * Core maple bus functionality
   *
 - *  Copyright (C) 2007, 2008 Adrian McMenamin
 + *  Copyright (C) 2007 - 2009 Adrian McMenamin
   *  Copyright (C) 2001 - 2008 Paul Mundt
 - *
 - * Based on 2.4 code by:
 - *
 - *  Copyright (C) 2000-2001 YAEGASHI Takeshi
 + *  Copyright (C) 2000 - 2001 YAEGASHI Takeshi
   *  Copyright (C) 2001 M. R. Brown
 - *  Copyright (C) 2001 Paul Mundt
 - *
 - * and others.
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file "COPYING" in the main directory of this archive
@@@ -26,7 -32,7 +26,7 @@@
  #include <mach/dma.h>
  #include <mach/sysasic.h>
  
 -MODULE_AUTHOR("Yaegashi Takeshi, Paul Mundt, M. R. Brown, Adrian McMenamin");
 +MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
  MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
  MODULE_LICENSE("GPL v2");
  MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");
@@@ -43,7 -49,7 +43,7 @@@ static LIST_HEAD(maple_sentq)
  /* mutex to protect queue of waiting packets */
  static DEFINE_MUTEX(maple_wlist_lock);
  
 -static struct maple_driver maple_dummy_driver;
 +static struct maple_driver maple_unsupported_device;
  static struct device maple_bus;
  static int subdevice_map[MAPLE_PORTS];
  static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
@@@ -56,9 -62,8 +56,9 @@@ struct maple_device_specify 
        int unit;
  };
  
 -static bool checked[4];
 -static struct maple_device *baseunits[4];
 +static bool checked[MAPLE_PORTS];
 +static bool empty[MAPLE_PORTS];
 +static struct maple_device *baseunits[MAPLE_PORTS];
  
  /**
   * maple_driver_register - register a maple driver
@@@ -92,20 -97,12 +92,20 @@@ void maple_driver_unregister(struct map
  EXPORT_SYMBOL_GPL(maple_driver_unregister);
  
  /* set hardware registers to enable next round of dma */
 -static void maplebus_dma_reset(void)
 +static void maple_dma_reset(void)
  {
        ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);
        /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */
        ctrl_outl(1, MAPLE_TRIGTYPE);
 -      ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED);
 +      /*
 +      * Maple system register
 +      * bits 31 - 16  timeout in units of 20nsec
 +      * bit 12        hard trigger - set 0 to keep responding to VBLANK
 +      * bits 9 - 8    set 00 for 2 Mbps, 01 for 1 Mbps
 +      * bits 3 - 0    delay (in 1.3ms) between VBLANK and start of DMA
 +      * max delay is 11
 +      */
 +      ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);
        ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
        ctrl_outl(1, MAPLE_ENABLE);
  }
@@@ -137,16 -134,21 +137,16 @@@ static void maple_release_device(struc
  {
        struct maple_device *mdev;
        struct mapleq *mq;
 -      if (!dev)
 -              return;
 +
        mdev = to_maple_dev(dev);
        mq = mdev->mq;
 -      if (mq) {
 -              if (mq->recvbufdcsp)
 -                      kmem_cache_free(maple_queue_cache, mq->recvbufdcsp);
 -              kfree(mq);
 -              mq = NULL;
 -      }
 +      kmem_cache_free(maple_queue_cache, mq->recvbuf);
 +      kfree(mq);
        kfree(mdev);
  }
  
  /**
 - * maple_add_packet - add a single instruction to the queue
 + * maple_add_packet - add a single instruction to the maple bus queue
   * @mdev: maple device
   * @function: function on device being queried
   * @command: maple command to add
  int maple_add_packet(struct maple_device *mdev, u32 function, u32 command,
        size_t length, void *data)
  {
 -      int locking, ret = 0;
 +      int ret = 0;
        void *sendbuf = NULL;
  
 -      mutex_lock(&maple_wlist_lock);
 -      /* bounce if device already locked */
 -      locking = mutex_is_locked(&mdev->mq->mutex);
 -      if (locking) {
 -              ret = -EBUSY;
 -              goto out;
 -      }
 -
 -      mutex_lock(&mdev->mq->mutex);
 -
        if (length) {
 -              sendbuf = kmalloc(length * 4, GFP_KERNEL);
 +              sendbuf = kzalloc(length * 4, GFP_KERNEL);
                if (!sendbuf) {
 -                      mutex_unlock(&mdev->mq->mutex);
 -                      ret = -ENOMEM;
 -                      goto out;
 -              }
 -              ((__be32 *)sendbuf)[0] = cpu_to_be32(function);
 -      }
 -
 -      mdev->mq->command = command;
 -      mdev->mq->length = length;
 -      if (length > 1)
 -              memcpy(sendbuf + 4, data, (length - 1) * 4);
 -      mdev->mq->sendbuf = sendbuf;
 -
 -      list_add(&mdev->mq->list, &maple_waitq);
 -out:
 -      mutex_unlock(&maple_wlist_lock);
 -      return ret;
 -}
 -EXPORT_SYMBOL_GPL(maple_add_packet);
 -
 -/**
 - * maple_add_packet_sleeps - add a single instruction to the queue
 - * @mdev: maple device
 - * @function: function on device being queried
 - * @command: maple command to add
 - * @length: length of command string (in 32 bit words)
 - * @data: remainder of command string
 - *
 - * Same as maple_add_packet(), but waits for the lock to become free.
 - */
 -int maple_add_packet_sleeps(struct maple_device *mdev, u32 function,
 -      u32 command, size_t length, void *data)
 -{
 -      int locking, ret = 0;
 -      void *sendbuf = NULL;
 -
 -      locking = mutex_lock_interruptible(&mdev->mq->mutex);
 -      if (locking) {
 -              ret = -EIO;
 -              goto out;
 -      }
 -
 -      if (length) {
 -              sendbuf = kmalloc(length * 4, GFP_KERNEL);
 -              if (!sendbuf) {
 -                      mutex_unlock(&mdev->mq->mutex);
                        ret = -ENOMEM;
                        goto out;
                }
        mdev->mq->sendbuf = sendbuf;
  
        mutex_lock(&maple_wlist_lock);
 -      list_add(&mdev->mq->list, &maple_waitq);
 +      list_add_tail(&mdev->mq->list, &maple_waitq);
        mutex_unlock(&maple_wlist_lock);
  out:
        return ret;
  }
 -EXPORT_SYMBOL_GPL(maple_add_packet_sleeps);
 +EXPORT_SYMBOL_GPL(maple_add_packet);
  
  static struct mapleq *maple_allocq(struct maple_device *mdev)
  {
        struct mapleq *mq;
  
 -      mq = kmalloc(sizeof(*mq), GFP_KERNEL);
 +      mq = kzalloc(sizeof(*mq), GFP_KERNEL);
        if (!mq)
                goto failed_nomem;
  
 +      INIT_LIST_HEAD(&mq->list);
        mq->dev = mdev;
 -      mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
 -      mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp);
 +      mq->recvbuf = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
        if (!mq->recvbuf)
                goto failed_p2;
 -      /*
 -       * most devices do not need the mutex - but
 -       * anything that injects block reads or writes
 -       * will rely on it
 -       */
 -      mutex_init(&mq->mutex);
 +      mq->recvbuf->buf = &((mq->recvbuf->bufx)[0]);
  
        return mq;
  
  failed_p2:
        kfree(mq);
  failed_nomem:
 +      dev_err(&mdev->dev, "could not allocate memory for device (%d, %d)\n",
 +              mdev->port, mdev->unit);
        return NULL;
  }
  
@@@ -211,16 -272,12 +211,16 @@@ static struct maple_device *maple_alloc
  {
        struct maple_device *mdev;
  
 +      /* zero this out to avoid kobj subsystem
 +      * thinking it has already been registered */
 +
        mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
        if (!mdev)
                return NULL;
  
        mdev->port = port;
        mdev->unit = unit;
 +
        mdev->mq = maple_allocq(mdev);
  
        if (!mdev->mq) {
        }
        mdev->dev.bus = &maple_bus_type;
        mdev->dev.parent = &maple_bus;
 +      init_waitqueue_head(&mdev->maple_wait);
        return mdev;
  }
  
  static void maple_free_dev(struct maple_device *mdev)
  {
 -      if (!mdev)
 -              return;
 -      if (mdev->mq) {
 -              if (mdev->mq->recvbufdcsp)
 -                      kmem_cache_free(maple_queue_cache,
 -                              mdev->mq->recvbufdcsp);
 -              kfree(mdev->mq);
 -      }
 +      kmem_cache_free(maple_queue_cache, mdev->mq->recvbuf);
 +      kfree(mdev->mq);
        kfree(mdev);
  }
  
@@@ -258,7 -320,7 +258,7 @@@ static void maple_build_block(struct ma
        maple_lastptr = maple_sendptr;
  
        *maple_sendptr++ = (port << 16) | len | 0x80000000;
 -      *maple_sendptr++ = PHYSADDR(mq->recvbuf);
 +      *maple_sendptr++ = PHYSADDR(mq->recvbuf->buf);
        *maple_sendptr++ =
            mq->command | (to << 8) | (from << 16) | (len << 24);
        while (len-- > 0)
@@@ -271,28 -333,20 +271,28 @@@ static void maple_send(void
        int i, maple_packets = 0;
        struct mapleq *mq, *nmq;
  
 -      if (!list_empty(&maple_sentq))
 +      if (!maple_dma_done())
                return;
 +
 +      /* disable DMA */
 +      ctrl_outl(0, MAPLE_ENABLE);
 +
 +      if (!list_empty(&maple_sentq))
 +              goto finish;
 +
        mutex_lock(&maple_wlist_lock);
 -      if (list_empty(&maple_waitq) || !maple_dma_done()) {
 +      if (list_empty(&maple_waitq)) {
                mutex_unlock(&maple_wlist_lock);
 -              return;
 +              goto finish;
        }
 -      mutex_unlock(&maple_wlist_lock);
 +
        maple_lastptr = maple_sendbuf;
        maple_sendptr = maple_sendbuf;
 -      mutex_lock(&maple_wlist_lock);
 +
        list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {
                maple_build_block(mq);
 -              list_move(&mq->list, &maple_sentq);
 +              list_del_init(&mq->list);
 +              list_add_tail(&mq->list, &maple_sentq);
                if (maple_packets++ > MAPLE_MAXPACKETS)
                        break;
        }
                        dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,
                                       PAGE_SIZE, DMA_BIDIRECTIONAL);
        }
 +
 +finish:
 +      maple_dma_reset();
  }
  
  /* check if there is a driver registered likely to match this device */
 -static int check_matching_maple_driver(struct device_driver *driver,
 +static int maple_check_matching_driver(struct device_driver *driver,
                                        void *devptr)
  {
        struct maple_driver *maple_drv;
  
  static void maple_detach_driver(struct maple_device *mdev)
  {
 -      if (!mdev)
 -              return;
        device_unregister(&mdev->dev);
 -      mdev = NULL;
  }
  
  /* process initial MAPLE_COMMAND_DEVINFO for each device or port */
@@@ -331,9 -385,9 +331,9 @@@ static void maple_attach_driver(struct 
  {
        char *p, *recvbuf;
        unsigned long function;
 -      int matched, retval;
 +      int matched, error;
  
 -      recvbuf = mdev->mq->recvbuf;
 +      recvbuf = mdev->mq->recvbuf->buf;
        /* copy the data as individual elements in
        * case of memory optimisation */
        memcpy(&mdev->devinfo.function, recvbuf + 4, 4);
        memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1);
        memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1);
        memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30);
 -      memcpy(&mdev->devinfo.product_licence[0], recvbuf + 52, 60);
        memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2);
        memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2);
        memcpy(mdev->product_name, mdev->devinfo.product_name, 30);
                else
                        break;
  
 -      printk(KERN_INFO "Maple device detected: %s\n",
 -              mdev->product_name);
 -      printk(KERN_INFO "Maple device: %s\n", mdev->product_licence);
 -
        function = be32_to_cpu(mdev->devinfo.function);
  
 +      dev_info(&mdev->dev, "detected %s: function 0x%lX: at (%d, %d)\n",
 +              mdev->product_name, function, mdev->port, mdev->unit);
 +
        if (function > 0x200) {
                /* Do this silently - as not a real device */
                function = 0;
 -              mdev->driver = &maple_dummy_driver;
 +              mdev->driver = &maple_unsupported_device;
                dev_set_name(&mdev->dev, "%d:0.port", mdev->port);
        } else {
 -              printk(KERN_INFO
 -                      "Maple bus at (%d, %d): Function 0x%lX\n",
 -                      mdev->port, mdev->unit, function);
 -
                matched =
                        bus_for_each_drv(&maple_bus_type, NULL, mdev,
 -                              check_matching_maple_driver);
 +                              maple_check_matching_driver);
  
                if (matched == 0) {
                        /* Driver does not exist yet */
 -                      printk(KERN_INFO
 -                              "No maple driver found.\n");
 -                      mdev->driver = &maple_dummy_driver;
 +                      dev_info(&mdev->dev, "no driver found\n");
 +                      mdev->driver = &maple_unsupported_device;
                }
                dev_set_name(&mdev->dev, "%d:0%d.%lX", mdev->port,
                             mdev->unit, function);
        }
 +
        mdev->function = function;
        mdev->dev.release = &maple_release_device;
 -      retval = device_register(&mdev->dev);
 -      if (retval) {
 -              printk(KERN_INFO
 -              "Maple bus: Attempt to register device"
 -              " (%x, %x) failed.\n",
 -              mdev->port, mdev->unit);
 +
 +      atomic_set(&mdev->busy, 0);
 +      error = device_register(&mdev->dev);
 +      if (error) {
 +              dev_warn(&mdev->dev, "could not register device at"
 +                      " (%d, %d), with error 0x%X\n", mdev->unit,
 +                      mdev->port, error);
                maple_free_dev(mdev);
                mdev = NULL;
                return;
   * port and unit then return 1 - allows identification
   * of which devices need to be attached or detached
   */
 -static int detach_maple_device(struct device *device, void *portptr)
 +static int check_maple_device(struct device *device, void *portptr)
  {
        struct maple_device_specify *ds;
        struct maple_device *mdev;
  static int setup_maple_commands(struct device *device, void *ignored)
  {
        int add;
 -      struct maple_device *maple_dev = to_maple_dev(device);
 -
 -      if ((maple_dev->interval > 0)
 -          && time_after(jiffies, maple_dev->when)) {
 -              /* bounce if we cannot lock */
 -              add = maple_add_packet(maple_dev,
 -                      be32_to_cpu(maple_dev->devinfo.function),
 +      struct maple_device *mdev = to_maple_dev(device);
 +      if (mdev->interval > 0 && atomic_read(&mdev->busy) == 0 &&
 +              time_after(jiffies, mdev->when)) {
 +              /* bounce if we cannot add */
 +              add = maple_add_packet(mdev,
 +                      be32_to_cpu(mdev->devinfo.function),
                        MAPLE_COMMAND_GETCOND, 1, NULL);
                if (!add)
 -                      maple_dev->when = jiffies + maple_dev->interval;
 +                      mdev->when = jiffies + mdev->interval;
        } else {
                if (time_after(jiffies, maple_pnp_time))
 -                      /* This will also bounce */
 -                      maple_add_packet(maple_dev, 0,
 -                              MAPLE_COMMAND_DEVINFO, 0, NULL);
 +                      /* Ensure we don't have block reads and devinfo
 +                      * calls interfering with one another - so flag the
 +                      * device as busy */
 +                      if (atomic_read(&mdev->busy) == 0) {
 +                              atomic_set(&mdev->busy, 1);
 +                              maple_add_packet(mdev, 0,
 +                                      MAPLE_COMMAND_DEVINFO, 0, NULL);
 +                      }
        }
        return 0;
  }
  /* VBLANK bottom half - implemented via workqueue */
  static void maple_vblank_handler(struct work_struct *work)
  {
 -      if (!list_empty(&maple_sentq) || !maple_dma_done())
 +      int x, locking;
 +      struct maple_device *mdev;
 +
 +      if (!maple_dma_done())
                return;
  
        ctrl_outl(0, MAPLE_ENABLE);
  
 +      if (!list_empty(&maple_sentq))
 +              goto finish;
 +
 +      /*
 +      * Set up essential commands - to fetch data and
 +      * check devices are still present
 +      */
        bus_for_each_dev(&maple_bus_type, NULL, NULL,
 -                       setup_maple_commands);
 +              setup_maple_commands);
 +
 +      if (time_after(jiffies, maple_pnp_time)) {
 +              /*
 +              * Scan the empty ports - bus is flakey and may have
 +              * mis-reported emptyness
 +              */
 +              for (x = 0; x < MAPLE_PORTS; x++) {
 +                      if (checked[x] && empty[x]) {
 +                              mdev = baseunits[x];
 +                              if (!mdev)
 +                                      break;
 +                              atomic_set(&mdev->busy, 1);
 +                              locking = maple_add_packet(mdev, 0,
 +                                      MAPLE_COMMAND_DEVINFO, 0, NULL);
 +                              if (!locking)
 +                                      break;
 +                              }
 +                      }
  
 -      if (time_after(jiffies, maple_pnp_time))
                maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL;
 -
 -      mutex_lock(&maple_wlist_lock);
 -      if (!list_empty(&maple_waitq) && list_empty(&maple_sentq)) {
 -              mutex_unlock(&maple_wlist_lock);
 -              maple_send();
 -      } else {
 -              mutex_unlock(&maple_wlist_lock);
        }
  
 -      maplebus_dma_reset();
 +finish:
 +      maple_send();
  }
  
 -/* handle devices added via hotplugs - placing them on queue for DEVINFO*/
 +/* handle devices added via hotplugs - placing them on queue for DEVINFO */
  static void maple_map_subunits(struct maple_device *mdev, int submask)
  {
        int retval, k, devcheck;
                ds.unit = k + 1;
                retval =
                    bus_for_each_dev(&maple_bus_type, NULL, &ds,
 -                                   detach_maple_device);
 +                                   check_maple_device);
                if (retval) {
                        submask = submask >> 1;
                        continue;
                        mdev_add = maple_alloc_dev(mdev->port, k + 1);
                        if (!mdev_add)
                                return;
 +                      atomic_set(&mdev_add->busy, 1);
                        maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO,
                                0, NULL);
                        /* mark that we are checking sub devices */
@@@ -532,45 -564,27 +531,45 @@@ static void maple_clean_submap(struct m
  }
  
  /* handle empty port or hotplug removal */
 -static void maple_response_none(struct maple_device *mdev,
 -                              struct mapleq *mq)
 -{
 -      if (mdev->unit != 0) {
 -              list_del(&mq->list);
 -              maple_clean_submap(mdev);
 -              printk(KERN_INFO
 -                     "Maple bus device detaching at (%d, %d)\n",
 -                     mdev->port, mdev->unit);
 +static void maple_response_none(struct maple_device *mdev)
 +{
 +      maple_clean_submap(mdev);
 +
 +      if (likely(mdev->unit != 0)) {
 +              /*
 +              * Block devices play up
 +              * and give the impression they have
 +              * been removed even when still in place or
 +              * trip the mtd layer when they have
 +              * really gone - this code traps that eventuality
 +              * and ensures we aren't overloaded with useless
 +              * error messages
 +              */
 +              if (mdev->can_unload) {
 +                      if (!mdev->can_unload(mdev)) {
 +                              atomic_set(&mdev->busy, 2);
 +                              wake_up(&mdev->maple_wait);
 +                              return;
 +                      }
 +              }
 +
 +              dev_info(&mdev->dev, "detaching device at (%d, %d)\n",
 +                      mdev->port, mdev->unit);
                maple_detach_driver(mdev);
                return;
 -      }
 -      if (!started || !fullscan) {
 -              if (checked[mdev->port] == false) {
 -                      checked[mdev->port] = true;
 -                      printk(KERN_INFO "No maple devices attached"
 -                              " to port %d\n", mdev->port);
 +      } else {
 +              if (!started || !fullscan) {
 +                      if (checked[mdev->port] == false) {
 +                              checked[mdev->port] = true;
 +                              empty[mdev->port] = true;
 +                              dev_info(&mdev->dev, "no devices"
 +                                      " to port %d\n", mdev->port);
 +                      }
 +                      return;
                }
 -              return;
        }
 -      maple_clean_submap(mdev);
 +      /* Some hardware devices generate false detach messages on unit 0 */
 +      atomic_set(&mdev->busy, 0);
  }
  
  /* preprocess hotplugs or scans */
@@@ -585,11 -599,8 +584,11 @@@ static void maple_response_devinfo(stru
                } else {
                        if (mdev->unit != 0)
                                maple_attach_driver(mdev);
 +                      if (mdev->unit == 0) {
 +                              empty[mdev->port] = false;
 +                              maple_attach_driver(mdev);
 +                      }
                }
 -              return;
        }
        if (mdev->unit == 0) {
                submask = recvbuf[2] & 0x1F;
        }
  }
  
 +static void maple_response_fileerr(struct maple_device *mdev, void *recvbuf)
 +{
 +      if (mdev->fileerr_handler) {
 +              mdev->fileerr_handler(mdev, recvbuf);
 +              return;
 +      } else
 +              dev_warn(&mdev->dev, "device at (%d, %d) reports"
 +                      "file error 0x%X\n", mdev->port, mdev->unit,
 +                      ((int *)recvbuf)[1]);
 +}
 +
  static void maple_port_rescan(void)
  {
        int i;
                if (checked[i] == false) {
                        fullscan = 0;
                        mdev = baseunits[i];
 -                      /*
 -                       *  test lock in case scan has failed
 -                       *  but device is still locked
 -                       */
 -                      if (mutex_is_locked(&mdev->mq->mutex))
 -                              mutex_unlock(&mdev->mq->mutex);
                        maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO,
                                0, NULL);
                }
  static void maple_dma_handler(struct work_struct *work)
  {
        struct mapleq *mq, *nmq;
 -      struct maple_device *dev;
 +      struct maple_device *mdev;
        char *recvbuf;
        enum maple_code code;
  
        ctrl_outl(0, MAPLE_ENABLE);
        if (!list_empty(&maple_sentq)) {
                list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {
 -                      recvbuf = mq->recvbuf;
 +                      mdev = mq->dev;
 +                      recvbuf = mq->recvbuf->buf;
 +                      dma_cache_sync(&mdev->dev, recvbuf, 0x400,
 +                              DMA_FROM_DEVICE);
                        code = recvbuf[0];
 -                      dev = mq->dev;
                        kfree(mq->sendbuf);
 -                      mutex_unlock(&mq->mutex);
                        list_del_init(&mq->list);
 -
                        switch (code) {
                        case MAPLE_RESPONSE_NONE:
 -                              maple_response_none(dev, mq);
 +                              maple_response_none(mdev);
                                break;
  
                        case MAPLE_RESPONSE_DEVINFO:
 -                              maple_response_devinfo(dev, recvbuf);
 +                              maple_response_devinfo(mdev, recvbuf);
 +                              atomic_set(&mdev->busy, 0);
                                break;
  
                        case MAPLE_RESPONSE_DATATRF:
 -                              if (dev->callback)
 -                                      dev->callback(mq);
 +                              if (mdev->callback)
 +                                      mdev->callback(mq);
 +                              atomic_set(&mdev->busy, 0);
 +                              wake_up(&mdev->maple_wait);
                                break;
  
                        case MAPLE_RESPONSE_FILEERR:
 +                              maple_response_fileerr(mdev, recvbuf);
 +                              atomic_set(&mdev->busy, 0);
 +                              wake_up(&mdev->maple_wait);
 +                              break;
 +
                        case MAPLE_RESPONSE_AGAIN:
                        case MAPLE_RESPONSE_BADCMD:
                        case MAPLE_RESPONSE_BADFUNC:
 -                              printk(KERN_DEBUG
 -                                     "Maple non-fatal error 0x%X\n",
 -                                     code);
 +                              dev_warn(&mdev->dev, "non-fatal error"
 +                                      " 0x%X at (%d, %d)\n", code,
 +                                      mdev->port, mdev->unit);
 +                              atomic_set(&mdev->busy, 0);
                                break;
  
                        case MAPLE_RESPONSE_ALLINFO:
 -                              printk(KERN_DEBUG
 -                                     "Maple - extended device information"
 -                                      " not supported\n");
 +                              dev_notice(&mdev->dev, "extended"
 +                              " device information request for (%d, %d)"
 +                              " but call is not supported\n", mdev->port,
 +                              mdev->unit);
 +                              atomic_set(&mdev->busy, 0);
                                break;
  
                        case MAPLE_RESPONSE_OK:
 +                              atomic_set(&mdev->busy, 0);
 +                              wake_up(&mdev->maple_wait);
                                break;
  
                        default:
                if (!fullscan)
                        maple_port_rescan();
                /* mark that we have been through the first scan */
 -              if (started == 0)
 -                      started = 1;
 +              started = 1;
        }
 -      maplebus_dma_reset();
 +      maple_send();
  }
  
 -static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id)
 +static irqreturn_t maple_dma_interrupt(int irq, void *dev_id)
  {
        /* Load everything into the bottom half */
        schedule_work(&maple_dma_process);
        return IRQ_HANDLED;
  }
  
 -static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id)
 +static irqreturn_t maple_vblank_interrupt(int irq, void *dev_id)
  {
        schedule_work(&maple_vblank_process);
        return IRQ_HANDLED;
  
  static int maple_set_dma_interrupt_handler(void)
  {
 -      return request_irq(HW_EVENT_MAPLE_DMA, maplebus_dma_interrupt,
 -              IRQF_SHARED, "maple bus DMA", &maple_dummy_driver);
 +      return request_irq(HW_EVENT_MAPLE_DMA, maple_dma_interrupt,
 +              IRQF_SHARED, "maple bus DMA", &maple_unsupported_device);
  }
  
  static int maple_set_vblank_interrupt_handler(void)
  {
 -      return request_irq(HW_EVENT_VSYNC, maplebus_vblank_interrupt,
 -              IRQF_SHARED, "maple bus VBLANK", &maple_dummy_driver);
 +      return request_irq(HW_EVENT_VSYNC, maple_vblank_interrupt,
 +              IRQF_SHARED, "maple bus VBLANK", &maple_unsupported_device);
  }
  
  static int maple_get_dma_buffer(void)
        return 0;
  }
  
 -static int match_maple_bus_driver(struct device *devptr,
 +static int maple_match_bus_driver(struct device *devptr,
                                  struct device_driver *drvptr)
  {
        struct maple_driver *maple_drv = to_maple_driver(drvptr);
@@@ -771,18 -765,16 +770,18 @@@ static void maple_bus_release(struct de
  {
  }
  
 -static struct maple_driver maple_dummy_driver = {
 +static struct maple_driver maple_unsupported_device = {
        .drv = {
 -              .name = "maple_dummy_driver",
 +              .name = "maple_unsupported_device",
                .bus = &maple_bus_type,
        },
  };
 -
 +/**
 + * maple_bus_type - core maple bus structure
 + */
  struct bus_type maple_bus_type = {
        .name = "maple",
 -      .match = match_maple_bus_driver,
 +      .match = maple_match_bus_driver,
        .uevent = maple_bus_uevent,
  };
  EXPORT_SYMBOL_GPL(maple_bus_type);
@@@ -796,8 -788,7 +795,8 @@@ static int __init maple_bus_init(void
  {
        int retval, i;
        struct maple_device *mdev[MAPLE_PORTS];
 -      ctrl_outl(0, MAPLE_STATE);
 +
 +      ctrl_outl(0, MAPLE_ENABLE);
  
        retval = device_register(&maple_bus);
        if (retval)
        if (retval)
                goto cleanup_device;
  
 -      retval = driver_register(&maple_dummy_driver.drv);
 +      retval = driver_register(&maple_unsupported_device.drv);
        if (retval)
                goto cleanup_bus;
  
        /* allocate memory for maple bus dma */
        retval = maple_get_dma_buffer();
        if (retval) {
 -              printk(KERN_INFO
 -                     "Maple bus: Failed to allocate Maple DMA buffers\n");
 +              dev_err(&maple_bus, "failed to allocate DMA buffers\n");
                goto cleanup_basic;
        }
  
        /* set up DMA interrupt handler */
        retval = maple_set_dma_interrupt_handler();
        if (retval) {
 -              printk(KERN_INFO
 -                     "Maple bus: Failed to grab maple DMA IRQ\n");
 +              dev_err(&maple_bus, "bus failed to grab maple "
 +                      "DMA IRQ\n");
                goto cleanup_dma;
        }
  
        /* set up VBLANK interrupt handler */
        retval = maple_set_vblank_interrupt_handler();
        if (retval) {
 -              printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n");
 +              dev_err(&maple_bus, "bus failed to grab VBLANK IRQ\n");
                goto cleanup_irq;
        }
  
 -      maple_queue_cache =
 -          kmem_cache_create("maple_queue_cache", 0x400, 0,
 -                            SLAB_HWCACHE_ALIGN, NULL);
 +      maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN);
  
        if (!maple_queue_cache)
                goto cleanup_bothirqs;
        /* setup maple ports */
        for (i = 0; i < MAPLE_PORTS; i++) {
                checked[i] = false;
 +              empty[i] = false;
                mdev[i] = maple_alloc_dev(i, 0);
 -              baseunits[i] = mdev[i];
                if (!mdev[i]) {
                        while (i-- > 0)
                                maple_free_dev(mdev[i]);
                        goto cleanup_cache;
                }
 +              baseunits[i] = mdev[i];
 +              atomic_set(&mdev[i]->busy, 1);
                maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL);
                subdevice_map[i] = 0;
        }
  
 -      /* setup maplebus hardware */
 -      maplebus_dma_reset();
 -      /* initial detection */
 +      maple_pnp_time = jiffies + HZ;
 +      /* prepare initial queue */
        maple_send();
 -      maple_pnp_time = jiffies;
 -      printk(KERN_INFO "Maple bus core now registered.\n");
 +      dev_info(&maple_bus, "bus core now registered\n");
  
        return 0;
  
@@@ -877,7 -871,7 +876,7 @@@ cleanup_dma
        free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);
  
  cleanup_basic:
 -      driver_unregister(&maple_dummy_driver.drv);
 +      driver_unregister(&maple_unsupported_device.drv);
  
  cleanup_bus:
        bus_unregister(&maple_bus_type);
@@@ -886,7 -880,7 +885,7 @@@ cleanup_device
        device_unregister(&maple_bus);
  
  cleanup:
 -      printk(KERN_INFO "Maple bus registration failed\n");
 +      printk(KERN_ERR "Maple bus registration failed\n");
        return retval;
  }
  /* Push init to later to ensure hardware gets detected */
index b433b8ac76d9968c5cc2b43e169e70ab55848926,1d2636a898c513872350a78f24d8bd1acad1a85a..92ea0ab44ce23cd141882dceed16889bc26a97b9
@@@ -33,8 -33,6 +33,8 @@@ struct sh_mobile_lcdc_chan 
        struct fb_info info;
        dma_addr_t dma_handle;
        struct fb_deferred_io defio;
 +      unsigned long frame_end;
 +      wait_queue_head_t frame_end_wait;
  };
  
  struct sh_mobile_lcdc_priv {
@@@ -228,10 -226,7 +228,10 @@@ static void sh_mobile_lcdc_deferred_io_
  static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
  {
        struct sh_mobile_lcdc_priv *priv = data;
 +      struct sh_mobile_lcdc_chan *ch;
        unsigned long tmp;
 +      int is_sub;
 +      int k;
  
        /* acknowledge interrupt */
        tmp = lcdc_read(priv, _LDINTR);
        tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */
        lcdc_write(priv, _LDINTR, tmp);
  
 -      /* disable clocks */
 -      sh_mobile_lcdc_clk_off(priv);
 +      /* figure out if this interrupt is for main or sub lcd */
 +      is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
 +
 +      /* wake up channel and disable clocks*/
 +      for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
 +              ch = &priv->ch[k];
 +
 +              if (!ch->enabled)
 +                      continue;
 +
 +              if (is_sub == lcdc_chan_is_sublcd(ch)) {
 +                      ch->frame_end = 1;
 +                      wake_up(&ch->frame_end_wait);
 +
 +                      sh_mobile_lcdc_clk_off(priv);
 +              }
 +      }
 +
        return IRQ_HANDLED;
  }
  
@@@ -469,27 -448,18 +469,27 @@@ static void sh_mobile_lcdc_stop(struct 
        struct sh_mobile_lcdc_board_cfg *board_cfg;
        int k;
  
 -      /* tell the board code to disable the panel */
 +      /* clean up deferred io and ask board code to disable panel */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
                ch = &priv->ch[k];
 -              board_cfg = &ch->cfg.board_cfg;
 -              if (board_cfg->display_off)
 -                      board_cfg->display_off(board_cfg->board_data);
  
 -              /* cleanup deferred io if enabled */
 +              /* deferred io mode:
 +               * flush frame, and wait for frame end interrupt
 +               * clean up deferred io and enable clock
 +               */
                if (ch->info.fbdefio) {
 +                      ch->frame_end = 0;
 +                      schedule_delayed_work(&ch->info.deferred_work, 0);
 +                      wait_event(ch->frame_end_wait, ch->frame_end);
                        fb_deferred_io_cleanup(&ch->info);
                        ch->info.fbdefio = NULL;
 +                      sh_mobile_lcdc_clk_on(priv);
                }
 +
 +              board_cfg = &ch->cfg.board_cfg;
 +              if (board_cfg->display_off)
 +                      board_cfg->display_off(board_cfg->board_data);
 +
        }
  
        /* stop the lcdc */
@@@ -682,26 -652,6 +682,26 @@@ static int sh_mobile_lcdc_set_bpp(struc
        return 0;
  }
  
 +static int sh_mobile_lcdc_suspend(struct device *dev)
 +{
 +      struct platform_device *pdev = to_platform_device(dev);
 +
 +      sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
 +      return 0;
 +}
 +
 +static int sh_mobile_lcdc_resume(struct device *dev)
 +{
 +      struct platform_device *pdev = to_platform_device(dev);
 +
 +      return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
 +}
 +
 +static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
 +      .suspend = sh_mobile_lcdc_suspend,
 +      .resume = sh_mobile_lcdc_resume,
 +};
 +
  static int sh_mobile_lcdc_remove(struct platform_device *pdev);
  
  static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
        }
  
        error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
-                           pdev->dev.bus_id, priv);
+                           dev_name(&pdev->dev), priv);
        if (error) {
                dev_err(&pdev->dev, "unable to request irq\n");
                goto err1;
                        dev_err(&pdev->dev, "unsupported interface type\n");
                        goto err1;
                }
 +              init_waitqueue_head(&priv->ch[i].frame_end_wait);
  
                switch (pdata->ch[i].chan) {
                case LCDC_CHAN_MAINLCD:
@@@ -911,7 -860,6 +911,7 @@@ static struct platform_driver sh_mobile
        .driver         = {
                .name           = "sh_mobile_lcdc_fb",
                .owner          = THIS_MODULE,
 +              .pm             = &sh_mobile_lcdc_dev_pm_ops,
        },
        .probe          = sh_mobile_lcdc_probe,
        .remove         = sh_mobile_lcdc_remove,
diff --combined lib/Makefile
index b2c09da02cae13fa974ec949600dee89ff7a0f66,8633d6be9d21afc5574147e906695cc7b84914e1..0dd9229fab7ebf914598558f7d79b36f89aecd66
@@@ -82,10 -82,8 +82,10 @@@ obj-$(CONFIG_HAVE_LMB) += lmb.
  
  obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o
  
- obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o
+ obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o
  
 +obj-$(CONFIG_NLATTR) += nlattr.o
 +
  hostprogs-y   := gen_crc32table
  clean-files   := crc32table.h