aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ps3/vuart.c53
-rw-r--r--drivers/ps3/vuart.h29
2 files changed, 78 insertions, 4 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
571int 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
604void 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,
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
index 34b360da9ff9..1be992d568c8 100644
--- a/drivers/ps3/vuart.h
+++ b/drivers/ps3/vuart.h
@@ -31,6 +31,13 @@ struct ps3_vuart_stats {
31 unsigned long disconnect_interrupts; 31 unsigned long disconnect_interrupts;
32}; 32};
33 33
34struct ps3_vuart_work {
35 struct work_struct work;
36 unsigned long trigger;
37 spinlock_t lock;
38 struct ps3_vuart_port_device* dev; /* to convert work to device */
39};
40
34/** 41/**
35 * struct ps3_vuart_port_priv - private vuart device data. 42 * struct ps3_vuart_port_priv - private vuart device data.
36 */ 43 */
@@ -49,6 +56,7 @@ struct ps3_vuart_port_priv {
49 struct list_head head; 56 struct list_head head;
50 } rx_list; 57 } rx_list;
51 struct ps3_vuart_stats stats; 58 struct ps3_vuart_stats stats;
59 struct ps3_vuart_work work;
52}; 60};
53 61
54/** 62/**
@@ -71,10 +79,6 @@ struct ps3_vuart_port_driver {
71int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); 79int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
72void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); 80void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
73 81
74int ps3_vuart_write(struct ps3_vuart_port_device *dev,
75 const void* buf, unsigned int bytes);
76int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
77 unsigned int bytes);
78static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( 82static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
79 struct device_driver *_drv) 83 struct device_driver *_drv)
80{ 84{
@@ -85,5 +89,22 @@ static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
85{ 89{
86 return container_of(_dev, struct ps3_vuart_port_device, core); 90 return container_of(_dev, struct ps3_vuart_port_device, core);
87} 91}
92static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device(
93 struct work_struct *_work)
94{
95 struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work,
96 work);
97 return vw->dev;
98}
99
100int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
101 unsigned int bytes);
102int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
103 unsigned int bytes);
104int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
105 unsigned int bytes);
106void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev);
107void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
108 unsigned int bytes);
88 109
89#endif 110#endif