#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/workqueue.h>
#include <asm/ps3.h>
#include <asm/firmware.h>
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
*
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;
}
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,
unsigned long disconnect_interrupts;
};
+struct ps3_vuart_work {
+ struct work_struct work;
+ unsigned long trigger;
+ spinlock_t lock;
+ struct ps3_vuart_port_device* dev; /* to convert work to device */
+};
+
/**
* struct ps3_vuart_port_priv - private vuart device data.
*/
struct list_head head;
} rx_list;
struct ps3_vuart_stats stats;
+ struct ps3_vuart_work work;
};
/**
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
-int ps3_vuart_write(struct ps3_vuart_port_device *dev,
- const void* buf, unsigned int bytes);
-int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
- unsigned int bytes);
static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
struct device_driver *_drv)
{
{
return container_of(_dev, struct ps3_vuart_port_device, core);
}
+static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device(
+ struct work_struct *_work)
+{
+ struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work,
+ work);
+ return vw->dev;
+}
+
+int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
+ unsigned int bytes);
+int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+ unsigned int bytes);
+int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
+ unsigned int bytes);
+void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev);
+void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
+ unsigned int bytes);
#endif