]> err.no Git - linux-2.6/blobdiff - drivers/ps3/vuart.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
[linux-2.6] / drivers / ps3 / vuart.c
index 90b3d1ca5172c2723d80a84842b9a4972171a59e..ec2d36a1bc67ae98c22b8cd2589572b05633f646 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <asm/ps3.h>
 
 #include <asm/firmware.h>
@@ -81,14 +82,6 @@ struct ports_bmp {
        u64 unused[3];
 } __attribute__ ((aligned (32)));
 
-/* redefine dev_dbg to do a syntax check */
-
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
-       const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
 #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
 static void __attribute__ ((unused)) _dump_ports_bmp(
        const struct ports_bmp* bmp, const char* func, int line)
@@ -567,6 +560,44 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
        return 0;
 }
 
+int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
+       unsigned int bytes)
+{
+       unsigned long flags;
+
+       if(dev->priv->work.trigger) {
+               dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n",
+                       __func__, __LINE__);
+               return -EAGAIN;
+       }
+
+       BUG_ON(!bytes);
+
+       PREPARE_WORK(&dev->priv->work.work, func);
+
+       spin_lock_irqsave(&dev->priv->work.lock, flags);
+       if(dev->priv->rx_list.bytes_held >= bytes) {
+               dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
+                       __func__, __LINE__, bytes);
+               schedule_work(&dev->priv->work.work);
+               spin_unlock_irqrestore(&dev->priv->work.lock, flags);
+               return 0;
+       }
+
+       dev->priv->work.trigger = bytes;
+       spin_unlock_irqrestore(&dev->priv->work.lock, flags);
+
+       dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__,
+               __LINE__, bytes, bytes);
+
+       return 0;
+}
+
+void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev)
+{
+       dev->priv->work.trigger = 0;
+}
+
 /**
  * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
  *
@@ -674,6 +705,15 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
        dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",
                __func__, __LINE__, lb->dbg_number, bytes);
 
+       spin_lock_irqsave(&dev->priv->work.lock, flags);
+       if(dev->priv->work.trigger
+               && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) {
+               dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n",
+                       __func__, __LINE__, dev->priv->work.trigger);
+               dev->priv->work.trigger = 0;
+               schedule_work(&dev->priv->work.work);
+       }
+       spin_unlock_irqrestore(&dev->priv->work.lock, flags);
        return 0;
 }
 
@@ -839,14 +879,19 @@ static int ps3_vuart_probe(struct device *_dev)
        INIT_LIST_HEAD(&dev->priv->rx_list.head);
        spin_lock_init(&dev->priv->rx_list.lock);
 
+       INIT_WORK(&dev->priv->work.work, NULL);
+       spin_lock_init(&dev->priv->work.lock);
+       dev->priv->work.trigger = 0;
+       dev->priv->work.dev = dev;
+
        if (++vuart_bus_priv.use_count == 1) {
 
-               result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
+               result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY,
                        (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq);
 
                if (result) {
                        dev_dbg(&dev->core,
-                               "%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
+                               "%s:%d: ps3_vuart_irq_setup failed (%d)\n",
                                __func__, __LINE__, result);
                        result = -EPERM;
                        goto fail_alloc_irq;
@@ -892,14 +937,14 @@ static int ps3_vuart_probe(struct device *_dev)
 fail_probe:
        ps3_vuart_set_interrupt_mask(dev, 0);
 fail_request_irq:
-       ps3_free_vuart_irq(vuart_bus_priv.virq);
+       ps3_vuart_irq_destroy(vuart_bus_priv.virq);
        vuart_bus_priv.virq = NO_IRQ;
 fail_alloc_irq:
        --vuart_bus_priv.use_count;
        kfree(dev->priv);
        dev->priv = NULL;
 fail_alloc:
-       vuart_bus_priv.devices[port_number] = 0;
+       vuart_bus_priv.devices[port_number] = NULL;
 fail_match:
        up(&vuart_bus_priv.probe_mutex);
        dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
@@ -925,12 +970,12 @@ static int ps3_vuart_remove(struct device *_dev)
                dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
                        __LINE__, dev->core.bus_id);
 
-       vuart_bus_priv.devices[dev->priv->port_number] = 0;
+       vuart_bus_priv.devices[dev->priv->port_number] = NULL;
 
        if (--vuart_bus_priv.use_count == 0) {
                BUG();
                free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
-               ps3_free_vuart_irq(vuart_bus_priv.virq);
+               ps3_vuart_irq_destroy(vuart_bus_priv.virq);
                vuart_bus_priv.virq = NO_IRQ;
        }
 
@@ -978,7 +1023,7 @@ int __init ps3_vuart_bus_init(void)
        pr_debug("%s:%d:\n", __func__, __LINE__);
 
        if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
-               return 0;
+               return -ENODEV;
 
        init_MUTEX(&vuart_bus_priv.probe_mutex);
        result = bus_register(&ps3_vuart_bus);