109 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			109 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "event_queue.h"
 | |
| #include "interrupt.h"
 | |
| #include "process.h"
 | |
| #include "list.h"
 | |
| #include "kmalloc.h"
 | |
| 
 | |
| #define EVENT_BUFFER_SIZE 32
 | |
| 
 | |
| struct event_queue {
 | |
| 	struct event buffer[EVENT_BUFFER_SIZE];
 | |
| 	struct list process_queue;
 | |
| 	int head;
 | |
| 	int tail;
 | |
| 	int overflow_count;
 | |
| };
 | |
| 
 | |
| struct event_queue event_queue_root;
 | |
| 
 | |
| struct event_queue * event_queue_create_root()
 | |
| {
 | |
| 	memset(&event_queue_root,0,sizeof(event_queue_root));
 | |
| 	return &event_queue_root;
 | |
| }
 | |
| 
 | |
| struct event_queue * event_queue_create()
 | |
| {
 | |
| 	struct event_queue *q = kmalloc(sizeof(*q));
 | |
| 	memset(q,0,sizeof(*q));
 | |
| 	return q;
 | |
| }
 | |
| 
 | |
| void event_queue_delete( struct event_queue *q )
 | |
| {
 | |
| 	kfree(q);
 | |
| }
 | |
| 
 | |
| /* INTERRUPT CONTEXT */
 | |
| 
 | |
| void event_queue_post( struct event_queue *q, struct event *e )
 | |
| {
 | |
| 	/* If ring buffer is full, return immediately. */
 | |
| 	int next = (q->head+1) % EVENT_BUFFER_SIZE;
 | |
| 	if(next==q->tail) {
 | |
| 		q->overflow_count++;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* Copy event to current buffer position */
 | |
| 	q->buffer[q->head] = *e;
 | |
| 
 | |
| 	/* Advance head pointer and wake up waiting process (if any) */
 | |
| 	q->head = next;
 | |
| 	process_wakeup(&q->process_queue);
 | |
| }
 | |
| 
 | |
| /* INTERRUPT CONTEXT */
 | |
| 
 | |
| void event_queue_post_root( uint16_t type, uint16_t code, int16_t x, int16_t y )
 | |
| {
 | |
| 	struct event e;
 | |
| 	e.type = type;
 | |
| 	e.code = code;
 | |
| 	e.x = x;
 | |
| 	e.y = y;
 | |
| 	event_queue_post(&event_queue_root,&e);
 | |
| }
 | |
| 
 | |
| static int event_queue_read_raw( struct event_queue *q, struct event *e, int size, int blocking )
 | |
| {
 | |
| 	int total=0;
 | |
| 
 | |
| 	if(size<sizeof(struct event)) return KERROR_INVALID_REQUEST;
 | |
| 
 | |
| 	interrupt_block();
 | |
| 
 | |
| 	while(size>=sizeof(struct event)) {
 | |
| 
 | |
| 		if(q->head==q->tail) {
 | |
| 			if(blocking && total==0) {
 | |
| 				process_wait(&q->process_queue);
 | |
| 				continue;
 | |
| 			} else {
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		*e = q->buffer[q->tail];
 | |
| 		q->tail = (q->tail+1) % EVENT_BUFFER_SIZE;
 | |
| 		e++;
 | |
| 		total++;
 | |
| 		size -= sizeof(struct event);
 | |
| 	}
 | |
| 
 | |
| 	interrupt_unblock();
 | |
| 
 | |
| 	return total;
 | |
| }
 | |
| 
 | |
| int event_queue_read( struct event_queue *q, struct event *e, int size )
 | |
| {
 | |
| 	return event_queue_read_raw(q,e,size,1);
 | |
| }
 | |
| 
 | |
| int event_queue_read_nonblock( struct event_queue *q, struct event *e, int size )
 | |
| {
 | |
| 	return event_queue_read_raw(q,e,size,0);
 | |
| }
 | |
| 
 |