2 #include "pvr_events.h"
3 #include "servicesint.h"
4 #include "sgx_bridge.h"
6 #include <linux/wait.h>
7 #include <linux/sched.h>
8 #include <linux/spinlock.h>
9 #include <linux/time.h>
10 #include <linux/uaccess.h>
12 #include <linux/notifier.h>
13 #include <linux/slab.h>
15 #include <plat/display.h>
17 static spinlock_t event_lock;
18 static struct list_head sync_wait_list;
19 static struct list_head flip_wait_list;
20 static struct notifier_block dss_nb;
22 static inline bool is_render_complete(const struct PVRSRV_SYNC_DATA *sync,
23 u32 write_ops_pending)
25 return (int)sync->ui32WriteOpsComplete - (int)write_ops_pending >= 0;
28 static void pvr_signal_sync_event(struct pvr_pending_sync_event *e,
29 const struct timeval *now)
31 e->event.tv_sec = now->tv_sec;
32 e->event.tv_usec = now->tv_usec;
34 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
36 wake_up_interruptible(&e->base.file_priv->event_wait);
39 int pvr_sync_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv,
40 const struct PVRSRV_KERNEL_SYNC_INFO *sync_info,
43 struct pvr_pending_sync_event *e;
47 e = kzalloc(sizeof(*e), GFP_KERNEL);
51 e->event.base.type = PVR_EVENT_SYNC;
52 e->event.base.length = sizeof(e->event);
53 e->event.sync_info = sync_info;
54 e->event.user_data = user_data;
55 e->base.event = &e->event.base;
56 e->base.file_priv = priv;
57 e->base.destroy = (void (*)(struct pvr_pending_event *))kfree;
58 e->base.write_ops_pending = sync_info->psSyncData->ui32WriteOpsPending;
60 do_gettimeofday(&now);
61 spin_lock_irqsave(&event_lock, flags);
63 if (priv->event_space < sizeof(e->event)) {
64 spin_unlock_irqrestore(&event_lock, flags);
69 priv->event_space -= sizeof(e->event);
71 list_add_tail(&e->base.link, &sync_wait_list);
72 if (is_render_complete(sync_info->psSyncData,
73 e->base.write_ops_pending))
74 pvr_signal_sync_event(e, &now);
76 spin_unlock_irqrestore(&event_lock, flags);
81 static void pvr_signal_flip_event(struct pvr_pending_flip_event *e,
82 const struct timeval *now)
84 e->event.tv_sec = now->tv_sec;
85 e->event.tv_usec = now->tv_usec;
87 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
89 wake_up_interruptible(&e->base.file_priv->event_wait);
92 int pvr_flip_event_req(struct PVRSRV_FILE_PRIVATE_DATA *priv,
94 enum pvr_sync_wait_seq_type type, u64 user_data)
96 struct pvr_pending_flip_event *e;
100 e = kzalloc(sizeof(*e), GFP_KERNEL);
105 case _PVR_SYNC_WAIT_FLIP:
106 e->event.base.type = PVR_EVENT_FLIP;
107 e->dss_event = OMAP_DSS_NOTIFY_GO_OVL;
109 case _PVR_SYNC_WAIT_UPDATE:
110 e->event.base.type = PVR_EVENT_UPDATE;
111 e->dss_event = OMAP_DSS_NOTIFY_UPDATE_OVL;
116 e->event.base.length = sizeof(e->event);
117 e->base.event = &e->event.base;
118 e->event.overlay = overlay;
119 e->event.user_data = user_data;
120 e->base.file_priv = priv;
121 e->base.destroy = (void (*)(struct pvr_pending_event *))kfree;
123 do_gettimeofday(&now);
124 spin_lock_irqsave(&event_lock, flags);
126 if (priv->event_space < sizeof(e->event)) {
127 spin_unlock_irqrestore(&event_lock, flags);
132 priv->event_space -= sizeof(e->event);
134 list_add_tail(&e->base.link, &flip_wait_list);
136 spin_unlock_irqrestore(&event_lock, flags);
138 return omap_dss_request_notify(e->dss_event, overlay);
141 static bool pvr_dequeue_event(struct PVRSRV_FILE_PRIVATE_DATA *priv,
142 size_t total, size_t max, struct pvr_pending_event **out)
144 struct pvr_pending_event *e;
148 spin_lock_irqsave(&event_lock, flags);
151 if (list_empty(&priv->event_list))
154 e = list_first_entry(&priv->event_list, struct pvr_pending_event, link);
155 if (e->event->length + total > max)
158 priv->event_space += e->event->length;
164 spin_unlock_irqrestore(&event_lock, flags);
169 ssize_t pvr_read(struct file *filp, char __user *buf, size_t count, loff_t *off)
171 struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data;
172 struct pvr_pending_event *e;
176 ret = wait_event_interruptible(priv->event_wait,
177 !list_empty(&priv->event_list));
183 while (pvr_dequeue_event(priv, total, count, &e)) {
184 if (copy_to_user(buf + total, e->event, e->event->length)) {
189 total += e->event->length;
196 unsigned int pvr_poll(struct file *filp, struct poll_table_struct *wait)
198 struct PVRSRV_FILE_PRIVATE_DATA *priv = filp->private_data;
199 unsigned int mask = 0;
201 poll_wait(filp, &priv->event_wait, wait);
203 if (!list_empty(&priv->event_list))
204 mask |= POLLIN | POLLRDNORM;
209 void pvr_handle_sync_events(void)
211 struct pvr_pending_sync_event *e;
212 struct pvr_pending_sync_event *t;
216 do_gettimeofday(&now);
218 spin_lock_irqsave(&event_lock, flags);
220 list_for_each_entry_safe(e, t, &sync_wait_list, base.link) {
221 if (!is_render_complete(e->event.sync_info->psSyncData,
222 e->base.write_ops_pending))
225 pvr_signal_sync_event(e, &now);
228 spin_unlock_irqrestore(&event_lock, flags);
231 static int dss_notifier_callback(struct notifier_block *nb,
232 unsigned long event, void *data)
234 struct pvr_pending_flip_event *e;
235 struct pvr_pending_flip_event *t;
238 long overlay = (long) data;
240 do_gettimeofday(&now);
242 spin_lock_irqsave(&event_lock, flags);
244 list_for_each_entry_safe(e, t, &flip_wait_list, base.link) {
245 if (!(e->dss_event & event))
247 if (e->event.overlay != overlay)
250 pvr_signal_flip_event(e, &now);
253 spin_unlock_irqrestore(&event_lock, flags);
258 void pvr_release_events(struct PVRSRV_FILE_PRIVATE_DATA *priv)
260 struct pvr_pending_event *w;
261 struct pvr_pending_event *z;
262 struct pvr_pending_sync_event *e;
263 struct pvr_pending_sync_event *t;
264 struct pvr_pending_flip_event *e2;
265 struct pvr_pending_flip_event *t2;
268 spin_lock_irqsave(&event_lock, flags);
270 /* Remove pending waits */
271 list_for_each_entry_safe(e, t, &sync_wait_list, base.link)
272 if (e->base.file_priv == priv) {
273 list_del(&e->base.link);
274 e->base.destroy(&e->base);
277 list_for_each_entry_safe(e2, t2, &flip_wait_list, base.link)
278 if (e2->base.file_priv == priv) {
279 list_del(&e2->base.link);
280 e2->base.destroy(&e2->base);
283 /* Remove unconsumed events */
284 list_for_each_entry_safe(w, z, &priv->event_list, link)
287 spin_unlock_irqrestore(&event_lock, flags);
290 void pvr_init_events(void)
292 spin_lock_init(&event_lock);
293 INIT_LIST_HEAD(&sync_wait_list);
294 INIT_LIST_HEAD(&flip_wait_list);
296 dss_nb.notifier_call = dss_notifier_callback;
297 omap_dss_register_notifier(&dss_nb);
300 void pvr_exit_events(void)
302 omap_dss_unregister_notifier(&dss_nb);