diff options
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 90b3d1ca5172..746298107d6f 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/workqueue.h> | ||
24 | #include <asm/ps3.h> | 25 | #include <asm/ps3.h> |
25 | 26 | ||
26 | #include <asm/firmware.h> | 27 | #include <asm/firmware.h> |
@@ -567,6 +568,44 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | |||
567 | return 0; | 568 | return 0; |
568 | } | 569 | } |
569 | 570 | ||
571 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | ||
572 | unsigned int bytes) | ||
573 | { | ||
574 | unsigned long flags; | ||
575 | |||
576 | if(dev->priv->work.trigger) { | ||
577 | dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", | ||
578 | __func__, __LINE__); | ||
579 | return -EAGAIN; | ||
580 | } | ||
581 | |||
582 | BUG_ON(!bytes); | ||
583 | |||
584 | PREPARE_WORK(&dev->priv->work.work, func); | ||
585 | |||
586 | spin_lock_irqsave(&dev->priv->work.lock, flags); | ||
587 | if(dev->priv->rx_list.bytes_held >= bytes) { | ||
588 | dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", | ||
589 | __func__, __LINE__, bytes); | ||
590 | schedule_work(&dev->priv->work.work); | ||
591 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | dev->priv->work.trigger = bytes; | ||
596 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | ||
597 | |||
598 | dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, | ||
599 | __LINE__, bytes, bytes); | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) | ||
605 | { | ||
606 | dev->priv->work.trigger = 0; | ||
607 | } | ||
608 | |||
570 | /** | 609 | /** |
571 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler | 610 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler |
572 | * | 611 | * |
@@ -674,6 +713,15 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) | |||
674 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", | 713 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", |
675 | __func__, __LINE__, lb->dbg_number, bytes); | 714 | __func__, __LINE__, lb->dbg_number, bytes); |
676 | 715 | ||
716 | spin_lock_irqsave(&dev->priv->work.lock, flags); | ||
717 | if(dev->priv->work.trigger | ||
718 | && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) { | ||
719 | dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", | ||
720 | __func__, __LINE__, dev->priv->work.trigger); | ||
721 | dev->priv->work.trigger = 0; | ||
722 | schedule_work(&dev->priv->work.work); | ||
723 | } | ||
724 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | ||
677 | return 0; | 725 | return 0; |
678 | } | 726 | } |
679 | 727 | ||
@@ -839,6 +887,11 @@ static int ps3_vuart_probe(struct device *_dev) | |||
839 | INIT_LIST_HEAD(&dev->priv->rx_list.head); | 887 | INIT_LIST_HEAD(&dev->priv->rx_list.head); |
840 | spin_lock_init(&dev->priv->rx_list.lock); | 888 | spin_lock_init(&dev->priv->rx_list.lock); |
841 | 889 | ||
890 | INIT_WORK(&dev->priv->work.work, NULL); | ||
891 | spin_lock_init(&dev->priv->work.lock); | ||
892 | dev->priv->work.trigger = 0; | ||
893 | dev->priv->work.dev = dev; | ||
894 | |||
842 | if (++vuart_bus_priv.use_count == 1) { | 895 | if (++vuart_bus_priv.use_count == 1) { |
843 | 896 | ||
844 | result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, | 897 | result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, |