diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ps3/vuart.c | 53 | ||||
-rw-r--r-- | drivers/ps3/vuart.h | 29 |
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 | ||
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, |
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 | ||
34 | struct 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 { | |||
71 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); | 79 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); |
72 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); | 80 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); |
73 | 81 | ||
74 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, | ||
75 | const void* buf, unsigned int bytes); | ||
76 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | ||
77 | unsigned int bytes); | ||
78 | static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( | 82 | static 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 | } |
92 | static 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 | |||
100 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | ||
101 | unsigned int bytes); | ||
102 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | ||
103 | unsigned int bytes); | ||
104 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | ||
105 | unsigned int bytes); | ||
106 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev); | ||
107 | void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | ||
108 | unsigned int bytes); | ||
88 | 109 | ||
89 | #endif | 110 | #endif |