diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-02-06 14:23:47 -0800 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-02-16 14:00:19 +1100 |
commit | ea1547d31153f8c3bdd32646f17d096d3108c838 (patch) | |
tree | d292396b7446be61318d7e70be443d88a68b32f1 /drivers/ps3/vuart.c | |
parent | 75c86e7422751c5be3caaf448d802839ec685725 (diff) |
[POWERPC] PS3: Vuart add async read
Add asynchronous read support to the PS3 vuart driver. This is needed to
support the PS3 system manager driver.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers/ps3/vuart.c')
-rw-r--r-- | drivers/ps3/vuart.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index 90b3d1ca517..746298107d6 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c @@ -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> @@ -567,6 +568,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 +713,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,6 +887,11 @@ 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, |