|
@@ -1,6 +1,5 @@
|
|
|
-h
|
|
|
// ===========================================================================
|
|
|
-// cyio.c
|
|
|
+// Cybook Event Manager - cyevent.c
|
|
|
// Copyright (C) 2008-2010 Bookeen - All rights reserved
|
|
|
// ===========================================================================
|
|
|
#include <linux/init.h>
|
|
@@ -14,132 +13,328 @@ h
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/pm.h>
|
|
|
#include <linux/proc_fs.h>
|
|
|
-
|
|
|
+#include <asm/hardware.h>
|
|
|
+#include <asm/uaccess.h>
|
|
|
+#include <asm/arch/gpio.h>
|
|
|
+#include <asm/arch/regs-gpio.h>
|
|
|
+#include <asm/arch/regs-irq.h>
|
|
|
+#include <asm-arm/arch-s3c2410/irqs.h>
|
|
|
+#include <asm-arm/arch-s3c2410/gpio.h>
|
|
|
+#include <linux/irq.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
#include <asm/arch/regs-gpio.h>
|
|
|
#include <asm/arch/regs-gpioj.h>
|
|
|
+#include <asm/io.h>
|
|
|
|
|
|
#include <cybook.h>
|
|
|
-
|
|
|
#include <linux/cyevent.h>
|
|
|
|
|
|
+// =============================================================================
|
|
|
+//#define DEBUG_MESSAGES
|
|
|
+//#define DEBUG_TRACEFUNC
|
|
|
+//#define VERBOSE_LEVEL INFO_DEBUG
|
|
|
+
|
|
|
+#define MODULE_NAME "CyEvent"
|
|
|
+// =============================================================================
|
|
|
#define CYEV_MAX_EVENT 20
|
|
|
-#define CYEV_REPEAT_DELAY (HZ/2); /* ~500ms */
|
|
|
-#define CYEV_CURRENT_VERSION 0x10 /* 1.0 */
|
|
|
+#define CYEV_MAX_DEV 5
|
|
|
+#define CYEV_REPEAT_DELAY (HZ/2) /* ~500ms */
|
|
|
+// =============================================================================
|
|
|
enum { INVALID = 0, VALID };
|
|
|
-
|
|
|
-struct
|
|
|
+// =============================================================================
|
|
|
+typedef struct sCyEv_PayList
|
|
|
{
|
|
|
char valid;
|
|
|
char wantRepeat;
|
|
|
char seen;
|
|
|
+ char repeat;
|
|
|
char unique;
|
|
|
- int repeatDelay;
|
|
|
+ unsigned long repeatDelay;
|
|
|
CyEvent_t payload;
|
|
|
} CyEv_PayList;
|
|
|
|
|
|
-CyEv_PayList *cyev_eventList[CYEV_MAX_EVENT];
|
|
|
-
|
|
|
+CyEv_PayList cyev_eventList[CYEV_MAX_EVENT];
|
|
|
+// =============================================================================
|
|
|
+/* We should change this to a linked list... */
|
|
|
+struct cyevent_device *DevList[CYEV_MAX_DEV];
|
|
|
+// =============================================================================
|
|
|
struct task_struct *openingTask = 0;
|
|
|
+static atomic_t waitingRepeat;
|
|
|
+// =============================================================================
|
|
|
+#ifdef DEBUG_MESSAGES
|
|
|
|
|
|
-/* TODO: Add a locking method for accessing the eventList */
|
|
|
+enum InfoLevel
|
|
|
+{
|
|
|
+ INFO_ERROR = 0,
|
|
|
+ INFO_WARNING,
|
|
|
+ INFO_NORMAL,
|
|
|
+ INFO_DEBUG,
|
|
|
+ INFO_VERBOSE,
|
|
|
+};
|
|
|
|
|
|
-// ===========================================================================
|
|
|
+# ifndef VERBOSE_LEVEL
|
|
|
+# define VERBOSE_LEVEL INFO_WARNING
|
|
|
+# endif
|
|
|
+
|
|
|
+# ifdef DEBUG_TRACEFUNC
|
|
|
+
|
|
|
+static int _dbg_FunctionLevel = 0;
|
|
|
+
|
|
|
+# define MSG(str) {\
|
|
|
+ int __i;\
|
|
|
+ printk(KERN_ALERT "+");\
|
|
|
+ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
|
|
|
+ printk("-");\
|
|
|
+ printk("||" str "\n");\
|
|
|
+}
|
|
|
+
|
|
|
+# define DBG(str, ...) {\
|
|
|
+ int __i;\
|
|
|
+ printk(KERN_ALERT "+");\
|
|
|
+ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
|
|
|
+ printk("-");\
|
|
|
+ printk("||" str "\n", __VA_ARGS__);\
|
|
|
+}
|
|
|
+
|
|
|
+# define INFOL(level, s) do {\
|
|
|
+ if (level <= VERBOSE_LEVEL) {\
|
|
|
+ int __i;\
|
|
|
+ printk(KERN_ALERT "+");\
|
|
|
+ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
|
|
|
+ printk("-");\
|
|
|
+ printk("<%d>%s:%s(): ", level, __FILE__, __func__); printk s; printk("\n");\
|
|
|
+ }\
|
|
|
+ } while(0)
|
|
|
+
|
|
|
+# define FUNC_IN() {\
|
|
|
+ int __i;\
|
|
|
+ _dbg_FunctionLevel++;\
|
|
|
+ printk(KERN_ALERT "+");\
|
|
|
+ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
|
|
|
+ printk("-");\
|
|
|
+ printk(">> %s() >>\n", __func__);\
|
|
|
+}
|
|
|
+
|
|
|
+# define FUNC_OUT() {\
|
|
|
+ int __i;\
|
|
|
+ printk(KERN_ALERT "+");\
|
|
|
+ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
|
|
|
+ printk("-");\
|
|
|
+ printk("<< %s() <<\n", __func__);\
|
|
|
+ _dbg_FunctionLevel--;\
|
|
|
+}
|
|
|
+
|
|
|
+# define FUNC_OUTR(val) {\
|
|
|
+ int __i;\
|
|
|
+ printk(KERN_ALERT "+");\
|
|
|
+ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\
|
|
|
+ printk("-");\
|
|
|
+ printk("<< %s() = %d <<\n", __func__, val);\
|
|
|
+ _dbg_FunctionLevel--;\
|
|
|
+}
|
|
|
+# else /* DEBUG_TRACEFUNC */
|
|
|
+
|
|
|
+# define MSG(str) do {\
|
|
|
+ printk(KERN_ALERT MODULE_NAME ": " str "\n");\
|
|
|
+} while(0)
|
|
|
+
|
|
|
+# define DBG(str, ...) do {\
|
|
|
+ printk(KERN_ALERT MODULE_NAME ": " str "\n", __VA_ARGS__);\
|
|
|
+} while(0)
|
|
|
+# define FUNC_IN() do {\
|
|
|
+} while(0)
|
|
|
+
|
|
|
+# define FUNC_OUT() do {\
|
|
|
+} while(0)
|
|
|
+
|
|
|
+# define FUNC_OUTR(val) do {\
|
|
|
+ printk(KERN_ALERT MODULE_NAME ": %s() return %d\n", __func__, val);\
|
|
|
+} while(0)
|
|
|
+
|
|
|
+# define INFOL(level, s) do {\
|
|
|
+ if (level <= VERBOSE_LEVEL) {\
|
|
|
+ printk("<%d>%s:%s(): ", level, __FILE__, __func__); printk s; printk("\n");\
|
|
|
+ }\
|
|
|
+ } while(0)
|
|
|
+
|
|
|
+# endif /* DEBUG_TRACEFUNC */
|
|
|
+#else /* DEBUG_MESSAGES */
|
|
|
+# define MSG(str)
|
|
|
+# define DBG(str, ...)
|
|
|
+# define FUNC_IN()
|
|
|
+# define FUNC_OUT()
|
|
|
+# define FUNC_OUTR(val)
|
|
|
+# define INFOL(level, s)
|
|
|
+# define INFO(s)
|
|
|
+#endif /* DEBUG_MESSAGES */
|
|
|
+
|
|
|
+#define DUMP_CYEVENT(lvl, ev) INFOL(lvl, ("Event: .type=%c, .flags=%02X, .version=%02X\n" \
|
|
|
+ ".data = { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X }",\
|
|
|
+ ev.type, ev.flags, ev.version, ev.data.raw[0], ev.data.raw[1], ev.data.raw[2], ev.data.raw[3], ev.data.raw[4], ev.data.raw[5],\
|
|
|
+ ev.data.raw[6], ev.data.raw[7], ev.data.raw[8], ev.data.raw[9], ev.data.raw[10], ev.data.raw[11], ev.data.raw[12]))
|
|
|
+#define DUMP_EVITEM(lvl, evi) INFOL(lvl, ("EvItem: .valid = %d, .wantRepeat = %d, .seen = %d, .repeat = %d, .unique = %d, .repeatDelay = %lu .payload:",\
|
|
|
+ evi.valid, evi.wantRepeat, evi.seen, evi.repeat, evi.unique, evi.repeatDelay)); DUMP_CYEVENT(lvl, evi.payload);
|
|
|
+// =============================================================================
|
|
|
+rwlock_t cyev_list_rwlock = RW_LOCK_UNLOCKED;
|
|
|
+// =============================================================================
|
|
|
+static void publish_read_event(unsigned char type);
|
|
|
+static void publish_empty_event(void);
|
|
|
+// =============================================================================
|
|
|
// List management
|
|
|
void CyEv_ClearEventList(void)
|
|
|
{
|
|
|
int i;
|
|
|
+
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ atomic_set(&waitingRepeat, 0);
|
|
|
+
|
|
|
+ write_lock(&cyev_list_rwlock);
|
|
|
+
|
|
|
for (i = 0; i < CYEV_MAX_EVENT; i++)
|
|
|
{
|
|
|
cyev_eventList[i].wantRepeat = false;
|
|
|
+ cyev_eventList[i].repeat = false;
|
|
|
cyev_eventList[i].seen = false;
|
|
|
cyev_eventList[i].unique = false;
|
|
|
cyev_eventList[i].repeatDelay = 0;
|
|
|
cyev_eventList[i].valid = INVALID;
|
|
|
}
|
|
|
+
|
|
|
+ write_unlock(&cyev_list_rwlock);
|
|
|
+
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
}
|
|
|
+int listPos = 0;
|
|
|
|
|
|
/* Get Next Event will invalidate the event if it is not marked as repeat */
|
|
|
/* After the event is selected, it will point to the next one */
|
|
|
/* We first start by the first event of the list then search for the first valid and return it */
|
|
|
-CyEvent_t *CyEv_GetNextEvent(void)
|
|
|
+CyEvent_t *CyEv_GetNextEvent(CyEvent_t *ret)
|
|
|
{
|
|
|
- static int listPos = 0;
|
|
|
int i;
|
|
|
- CyEvent_t ret = NULL;
|
|
|
-
|
|
|
+ char foundPayload = 0;
|
|
|
+ CyEv_PayList *cur;
|
|
|
+
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ write_lock(&cyev_list_rwlock);
|
|
|
+
|
|
|
/* Scan the list starting from the last position stored */
|
|
|
for(i = listPos; i < (CYEV_MAX_EVENT + listPos); i++)
|
|
|
{
|
|
|
/* Stop on the first "VALID" event */
|
|
|
- if (cyev_eventList[i % CYEV_MAX_EVENT].valid == VALID)
|
|
|
- {
|
|
|
+ cur = &(cyev_eventList[i % CYEV_MAX_EVENT]);
|
|
|
+ //INFOL(INFO_VERBOSE, ("Position %d / %d", i % CYEV_MAX_EVENT, CYEV_MAX_EVENT));
|
|
|
+ if (cur->valid == VALID)
|
|
|
+ {
|
|
|
+ DUMP_EVITEM(INFO_DEBUG, (*cur));
|
|
|
+
|
|
|
/* We already send this repeatable event. Did the delay occur ?
|
|
|
if not, ignore it and go to the next one */
|
|
|
- if ( (cyev_eventList[i % CYEV_MAX_EVENT].seen == true) &&
|
|
|
- (cyev_eventList[i % CYEV_MAX_EVENT].wantRepeat == true) )
|
|
|
+ if ( (cur->seen == true) &&
|
|
|
+ (cur->wantRepeat == true) )
|
|
|
{
|
|
|
- if (cyev_eventList[i % CYEV_MAX_EVENT].repeatDelay < jiffies) )
|
|
|
+ if (cur->repeatDelay > jiffies)
|
|
|
{
|
|
|
+ INFOL(INFO_DEBUG, ("Event delay not occured [%lu vs %lu (%lu)]...",
|
|
|
+ cur->repeatDelay, jiffies, cur->repeatDelay - jiffies));
|
|
|
continue;
|
|
|
}
|
|
|
- else /* if (cyev_eventList[i % CYEV_MAX_EVENT].repeatDelay >= jiffies) ) */
|
|
|
+ else /* if (cur->repeatDelay >= jiffies) */
|
|
|
{
|
|
|
/* Set the Repeat flag to true */
|
|
|
- cyev_eventList[i % CYEV_MAX_EVENT].payload.flags |= CYEVENT_FLAG_REPEATEVENT;
|
|
|
+ INFOL(INFO_DEBUG, ("Event repeating... (%d)", atomic_read(&waitingRepeat)));
|
|
|
+ if (cur->repeat == false)
|
|
|
+ {
|
|
|
+ atomic_dec(&waitingRepeat); /* Ack the repeat event */
|
|
|
+ }
|
|
|
+ INFOL(INFO_DEBUG, ("waiting (%d) (repeat:%d)", atomic_read(&waitingRepeat), cur->repeat));
|
|
|
+ cur->payload.flags |= CYEVENT_FLAG_REPEATEVENT;
|
|
|
+ cur->repeat = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- cyev_eventList[i % CYEV_MAX_EVENT].seen = true;
|
|
|
+ cur->seen = true;
|
|
|
|
|
|
- /* Return the event */
|
|
|
- ret = &(cyev_eventList[i % CYEV_MAX_EVENT].payload);
|
|
|
-
|
|
|
+ /* Return the event and do not give real access to the list */
|
|
|
+ memcpy(ret, &(cur->payload), sizeof(CyEvent_t));
|
|
|
+ foundPayload = 1;
|
|
|
/* If the event is not a repeatable event, invalidate it! */
|
|
|
- if (cyev_eventList[i % CYEV_MAX_EVENT].wantRepeat == false)
|
|
|
+ if (cur->wantRepeat == false)
|
|
|
{
|
|
|
- cyev_eventList[i % CYEV_MAX_EVENT].valid = INVALID;
|
|
|
+ INFOL(INFO_VERBOSE, ("Non-repeat event, will invalidate it"));
|
|
|
+ cur->valid = INVALID;
|
|
|
}
|
|
|
|
|
|
/* Update the index for the next element to scan */
|
|
|
- listPos = (listPos + i + 1) % CYEV_MAX_EVENT;
|
|
|
+ listPos = (i + 1) % CYEV_MAX_EVENT;
|
|
|
+ INFOL(INFO_DEBUG, ("Next event slot: %d", listPos));
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- return ret; /* We will return NULL if no valid payload */
|
|
|
+
|
|
|
+ write_unlock(&cyev_list_rwlock);
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
+ if (foundPayload == 1)
|
|
|
+ return ret; /* We will return NULL if no valid payload */
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
-int isEventNotDuplicate(CyEvent_t *CyEvent)
|
|
|
+int isEventNotDuplicate(CyEvent_t *CyEvent, unsigned char flagMask)
|
|
|
{
|
|
|
int i;
|
|
|
- CyEvent_t *cur:
|
|
|
+ int ret = true;
|
|
|
+ CyEvent_t *cur;
|
|
|
+
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ read_lock(&cyev_list_rwlock);
|
|
|
+
|
|
|
for(i = 0; i < CYEV_MAX_EVENT; i++)
|
|
|
{
|
|
|
cur = &(cyev_eventList[i].payload);
|
|
|
- if (cyev_eventList[i].unique == true)
|
|
|
+ /* The event must be valid to be treated as unique, else invalid event are ignored */
|
|
|
+ if ( (cyev_eventList[i].valid == VALID) &&
|
|
|
+ (cyev_eventList[i].unique == true) )
|
|
|
{
|
|
|
- if (cur->type == CyEvent->type) /* To be verified */
|
|
|
- return false;
|
|
|
+ if ( (cur->type == CyEvent->type) &&
|
|
|
+ ((cyev_eventList[i].payload.flags & flagMask) == (CyEvent->flags & flagMask)) )
|
|
|
+ {
|
|
|
+ ret = false;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- return true;
|
|
|
+
|
|
|
+exit:
|
|
|
+ read_unlock(&cyev_list_rwlock);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-int CyEv_AddNewEvent(CyEvent_t *CyEvent, char wantRepeat, char wantUnique)
|
|
|
+int CyEv_AddNewEvent(CyEvent_t *CyEvent, char wantRepeat, char wantUnique, unsigned char flagMask)
|
|
|
{
|
|
|
/* Search for the first "invalid" event, then put the given CyEvent in it. */
|
|
|
/* If no slot is valid, return an error */
|
|
|
int i;
|
|
|
int ret = -EIO; /* TODO: find a better error code.*/
|
|
|
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
/* If wantUnique, first check that there is not another unique event */
|
|
|
- if ((wantUnique) && !isEventNotDuplicate(CyEvent))
|
|
|
+ if ((wantUnique) && !isEventNotDuplicate(CyEvent, flagMask))
|
|
|
goto exit;
|
|
|
|
|
|
+ write_lock(&cyev_list_rwlock);
|
|
|
+
|
|
|
/* Scan the list starting from the last position stored */
|
|
|
- for(i = 0; i < CYEV_MAX_EVENT; i++)
|
|
|
+ for(i = listPos; i < (CYEV_MAX_EVENT + listPos); i++)
|
|
|
{
|
|
|
- /* Stop on the first "VALID" event */
|
|
|
+ /* Stop on the first "INVALID" event */
|
|
|
if (cyev_eventList[i].valid == INVALID)
|
|
|
{
|
|
|
/* Store the event */
|
|
@@ -148,12 +343,16 @@ int CyEv_AddNewEvent(CyEvent_t *CyEvent, char wantRepeat, char wantUnique)
|
|
|
/* Force version in the structure */
|
|
|
cyev_eventList[i].payload.version = CYEV_CURRENT_VERSION;
|
|
|
cyev_eventList[i].valid = VALID;
|
|
|
+ cyev_eventList[i].seen = false;
|
|
|
+ cyev_eventList[i].repeat = false;
|
|
|
+
|
|
|
if (wantUnique)
|
|
|
cyev_eventList[i].unique = true;
|
|
|
else
|
|
|
cyev_eventList[i].unique = false;
|
|
|
if (wantRepeat)
|
|
|
{
|
|
|
+ atomic_inc(&waitingRepeat);
|
|
|
cyev_eventList[i].wantRepeat = true;
|
|
|
cyev_eventList[i].repeatDelay = jiffies + CYEV_REPEAT_DELAY;
|
|
|
}
|
|
@@ -168,30 +367,42 @@ int CyEv_AddNewEvent(CyEvent_t *CyEvent, char wantRepeat, char wantUnique)
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+ write_unlock(&cyev_list_rwlock);
|
|
|
|
|
|
exit:
|
|
|
+ FUNC_OUTR(ret);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
/* Return 0 if event found and updated, or anything else */
|
|
|
/* We could ONLY update event that are declared as unique */
|
|
|
-int CyEv_UpdateUniqueEvent(CyEvent_t *CyEvent, char wantRepeat)
|
|
|
+int CyEv_UpdateUniqueEvent(CyEvent_t *CyEvent, char wantRepeat, unsigned char flagMask)
|
|
|
{
|
|
|
int i;
|
|
|
int ret = -1;
|
|
|
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
/* Search for the event */
|
|
|
+ write_lock(&cyev_list_rwlock);
|
|
|
for(i = 0; i < CYEV_MAX_EVENT; i++)
|
|
|
{
|
|
|
- if ( (cyev_eventList[i].unique == true) &&
|
|
|
- (cyev_eventList[i].payload.type == CyEvent.type) )
|
|
|
+ if ( (cyev_eventList[i].valid == VALID) &&
|
|
|
+ (cyev_eventList[i].unique == true) &&
|
|
|
+ ((cyev_eventList[i].payload.flags & flagMask) == (CyEvent->flags & flagMask)) &&
|
|
|
+ (cyev_eventList[i].payload.type == CyEvent->type) )
|
|
|
{ /* Found it ! Now update the fields */
|
|
|
memcpy(&(cyev_eventList[i].payload), CyEvent, sizeof(CyEvent_t));
|
|
|
|
|
|
+ cyev_eventList[i].seen = false;
|
|
|
+
|
|
|
if (wantRepeat)
|
|
|
{
|
|
|
cyev_eventList[i].wantRepeat = true;
|
|
|
+ cyev_eventList[i].repeat = false;
|
|
|
cyev_eventList[i].repeatDelay = jiffies + CYEV_REPEAT_DELAY;
|
|
|
+ if (cyev_eventList[i].repeat == true)
|
|
|
+ atomic_inc(&waitingRepeat);
|
|
|
}
|
|
|
else
|
|
|
cyev_eventList[i].wantRepeat = false;
|
|
@@ -202,6 +413,35 @@ int CyEv_UpdateUniqueEvent(CyEvent_t *CyEvent, char wantRepeat)
|
|
|
ret = 0;
|
|
|
}
|
|
|
}
|
|
|
+ write_unlock(&cyev_list_rwlock);
|
|
|
+ FUNC_OUTR(ret);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int CyEv_InvalidateUniqueEvent (CyEvent_t *CyEvent)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ /* Search for the event */
|
|
|
+ write_lock(&cyev_list_rwlock);
|
|
|
+ for ( i = 0; i < CYEV_MAX_EVENT; i++ )
|
|
|
+ {
|
|
|
+ if ( (cyev_eventList[i].valid == VALID) &&
|
|
|
+ (cyev_eventList[i].unique == true) &&
|
|
|
+ (cyev_eventList[i].payload.type == CyEvent->type) )
|
|
|
+ { /* Found it ! Now update the fields */
|
|
|
+ INFOL(INFO_DEBUG, ("Found event..."));
|
|
|
+ cyev_eventList[i].valid = INVALID;
|
|
|
+ ret = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ write_unlock(&cyev_list_rwlock);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -210,23 +450,40 @@ int CyEv_InvalidateRepeatableEvent(CyEvent_t *CyEvent)
|
|
|
int i;
|
|
|
int ret = -1;
|
|
|
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
/* Search for the event */
|
|
|
+ write_lock(&cyev_list_rwlock);
|
|
|
for(i = 0; i < CYEV_MAX_EVENT; i++)
|
|
|
{
|
|
|
- if ( (cyev_eventList[i].wantRepeat == true) &&
|
|
|
- (cyev_eventList[i].payload.type == CyEvent.type) )
|
|
|
+ if ( (cyev_eventList[i].valid == VALID) &&
|
|
|
+ (cyev_eventList[i].wantRepeat == true) &&
|
|
|
+ (cyev_eventList[i].payload.type == CyEvent->type) )
|
|
|
{ /* Found it ! Now update the fields */
|
|
|
-
|
|
|
+ INFOL(INFO_DEBUG, ("Found event..."));
|
|
|
/* In case the event has not been eaten, just remove the "repeat want"
|
|
|
ie: do not invalidate it */
|
|
|
cyev_eventList[i].wantRepeat = false;
|
|
|
|
|
|
- if (cyev_eventList[i].seen == true)
|
|
|
+ if (cyev_eventList[i].repeat == true)
|
|
|
+ {
|
|
|
+ INFOL(INFO_DEBUG, ("Was repeating..."));
|
|
|
+ /* set the event "end of repeat" flag */
|
|
|
+ cyev_eventList[i].payload.flags |= CYEVENT_FLAG_ENDOFREPEAT;
|
|
|
+ cyev_eventList[i].payload.flags &= ~(CYEVENT_FLAG_REPEATEVENT);
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- /* set the event "end of repeat" flag */
|
|
|
- cyev_eventList[i].payload.flags |= CYEVENT_FLAG_ENDOFREPEAT;
|
|
|
+ INFOL(INFO_DEBUG, ("Repeat not done... (%d)", atomic_read(&waitingRepeat)));
|
|
|
+ atomic_dec(&waitingRepeat); /* One less waiting event... */
|
|
|
+ INFOL(INFO_DEBUG, ("waiting (%d)", atomic_read(&waitingRepeat)));
|
|
|
+ if (cyev_eventList[i].seen == true)
|
|
|
+ cyev_eventList[i].valid = INVALID;
|
|
|
}
|
|
|
|
|
|
+ cyev_eventList[i].seen = false;
|
|
|
+ cyev_eventList[i].repeat = false;
|
|
|
+
|
|
|
if (openingTask)
|
|
|
wake_up_process(openingTask);
|
|
|
|
|
@@ -234,10 +491,11 @@ int CyEv_InvalidateRepeatableEvent(CyEvent_t *CyEvent)
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ write_unlock(&cyev_list_rwlock);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
return ret;
|
|
|
}
|
|
|
-
|
|
|
// ===========================================================================
|
|
|
|
|
|
|
|
@@ -245,90 +503,168 @@ int CyEv_InvalidateRepeatableEvent(CyEvent_t *CyEvent)
|
|
|
// External event managment
|
|
|
int CyEvent_PushNewEvent(CyEvent_t *CyEvent, char wantRepeat)
|
|
|
{
|
|
|
+ int ret = -1;
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
if (wantRepeat)
|
|
|
- return CyEv_AddNewEvent(CyEvent, wantRepeat, true);
|
|
|
+ ret = CyEv_AddNewEvent(CyEvent, wantRepeat, true, 0);
|
|
|
else
|
|
|
- return CyEv_AddNewEvent(CyEvent, wantRepeat, false);
|
|
|
+ ret = CyEv_AddNewEvent(CyEvent, wantRepeat, false, 0);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
+ return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(CyEvent_PushNewEvent);
|
|
|
|
|
|
+int CyEvent_PushNewUniqueEvent(CyEvent_t *CyEvent)
|
|
|
+{
|
|
|
+ return CyEv_AddNewEvent(CyEvent, false, true, 0);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(CyEvent_PushNewUniqueEvent);
|
|
|
+
|
|
|
+int CyEvent_PushOrUpdateUniqueEventFlaged(CyEvent_t *CyEvent, char wantRepeat, unsigned char flagMask)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ /* For now a simple call to AddNewEvent */
|
|
|
+ ret = CyEv_UpdateUniqueEvent(CyEvent, wantRepeat, flagMask);
|
|
|
+
|
|
|
+ if (ret != 0) /* The event is not present */
|
|
|
+ ret = CyEv_AddNewEvent(CyEvent, wantRepeat, true, flagMask);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(CyEvent_PushOrUpdateUniqueEventFlaged);
|
|
|
+
|
|
|
int CyEvent_PushOrUpdateUniqueEvent(CyEvent_t *CyEvent, char wantRepeat)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
/* For now a simple call to AddNewEvent */
|
|
|
- ret = CyEv_UpdateUniqueEvent(CyEvent, wantRepeat);
|
|
|
+ ret = CyEv_UpdateUniqueEvent(CyEvent, wantRepeat, 0);
|
|
|
|
|
|
if (ret != 0) /* The event is not present */
|
|
|
- ret = CyEv_AddNewEvent(CyEvent, wantRepeat, true);
|
|
|
-
|
|
|
+ ret = CyEv_AddNewEvent(CyEvent, wantRepeat, true, 0);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(CyEvent_PushOrUpdateUniqueEvent);
|
|
|
|
|
|
+int CyEvent_InvalidateUniqueEvent(CyEvent_t *CyEvent)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ ret = CyEv_InvalidateUniqueEvent(CyEvent);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(CyEvent_InvalidateUniqueEvent);
|
|
|
+
|
|
|
int CyEvent_InvalidateRepeatableEvent(CyEvent_t *CyEvent)
|
|
|
{
|
|
|
- ret = CyEv_InvalidateRepeatableEvent(CyEvent);
|
|
|
+ int ret;
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ ret = CyEv_InvalidateRepeatableEvent(CyEvent);
|
|
|
+
|
|
|
+ FUNC_OUTR(ret);
|
|
|
+ return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(CyEvent_InvalidateRepeatableEvent);
|
|
|
|
|
|
// ===========================================================================
|
|
|
static int ev_open(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
/* Clear pending event list... */
|
|
|
CyEv_ClearEventList();
|
|
|
|
|
|
+ FUNC_OUT();
|
|
|
return 0;
|
|
|
}
|
|
|
// ---------------------------------------------------------------------------
|
|
|
static int ev_release(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
/* Clear pending event list... */
|
|
|
CyEv_ClearEventList();
|
|
|
|
|
|
+ FUNC_OUT();
|
|
|
return 0;
|
|
|
}
|
|
|
// ---------------------------------------------------------------------------
|
|
|
-ssize_t ev_read(struct file *file, char *buf, size_t count, loff_t *ppos)
|
|
|
+
|
|
|
+ssize_t ev_read (struct file *file, char *buf, size_t count, loff_t *ppos)
|
|
|
{
|
|
|
- int nBytes = sizeof(CyEvent_t);
|
|
|
- int ret = -EIO;
|
|
|
- CyEvent_t *CyEvent = NULL;
|
|
|
-
|
|
|
- if (count < nBytes)
|
|
|
- {
|
|
|
- ret = -EINVAL;
|
|
|
- goto exit;
|
|
|
- }
|
|
|
+ int nBytes = sizeof (CyEvent_t);
|
|
|
+ int ret = -EIO;
|
|
|
+ int waitCount;
|
|
|
+ CyEvent_t CyEvent;
|
|
|
|
|
|
- while (1)
|
|
|
- {
|
|
|
- if ((CyEvent = CyEv_GetNextEvent()) != NULL)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- openingTask = current;
|
|
|
- set_current_state(TASK_INTERRUPTIBLE);
|
|
|
- schedule();
|
|
|
- set_current_state(TASK_RUNNING);
|
|
|
- openingTask = 0;
|
|
|
-
|
|
|
- if (signal_pending(current))
|
|
|
- {
|
|
|
- ret = -ERESTARTSYS;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (CyEvent != NULL)
|
|
|
- {
|
|
|
- nRes = copy_to_user(buf, &CyEvent, nBytes);
|
|
|
- if (!nRes)
|
|
|
- nRes = nBytes;
|
|
|
- }
|
|
|
+ //FUNC_IN();
|
|
|
|
|
|
- return ret;
|
|
|
+ if ( count < nBytes )
|
|
|
+ {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ while ( 1 )
|
|
|
+ {
|
|
|
+ //printk(KERN_ERR "CyEvent: Check new event...\n");
|
|
|
+ if ( CyEv_GetNextEvent(&CyEvent) != NULL )
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ waitCount = atomic_read(&waitingRepeat);
|
|
|
+
|
|
|
+ if (waitCount == 0) /* If there are some waiting event, the list is not empty */
|
|
|
+ publish_empty_event();
|
|
|
+
|
|
|
+ openingTask = current;
|
|
|
+ set_current_state(TASK_INTERRUPTIBLE);
|
|
|
+
|
|
|
+ /* If there are some waiting repeat, schedule with a timeout, or else,
|
|
|
+ just go out of the schedule queue */
|
|
|
+ INFOL(INFO_DEBUG, ("Waiting repeat: %d", waitCount));
|
|
|
+
|
|
|
+ if ( waitCount > 0 )
|
|
|
+ schedule_timeout(CYEV_REPEAT_DELAY / 10);
|
|
|
+ else
|
|
|
+ schedule();
|
|
|
+
|
|
|
+ set_current_state(TASK_RUNNING);
|
|
|
+ openingTask = 0;
|
|
|
+
|
|
|
+ if ( signal_pending(current) )
|
|
|
+ {
|
|
|
+ ret = -ERESTARTSYS;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( ret != -ERESTARTSYS )
|
|
|
+ {
|
|
|
+ ret = copy_to_user(buf, &CyEvent, nBytes);
|
|
|
+ if ( !ret )
|
|
|
+ ret = nBytes;
|
|
|
+ publish_read_event(CyEvent.type);
|
|
|
+ }
|
|
|
+
|
|
|
+exit:
|
|
|
+ //FUNC_OUTR(ret);
|
|
|
+ return ret;
|
|
|
}
|
|
|
// ---------------------------------------------------------------------------
|
|
|
static int ev_ioctl(struct inode *inode, struct file *file,
|
|
@@ -336,72 +672,90 @@ static int ev_ioctl(struct inode *inode, struct file *file,
|
|
|
{
|
|
|
int ret = -EINVAL;
|
|
|
unsigned long value;
|
|
|
+ int i;
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
switch(cmd)
|
|
|
{
|
|
|
default:
|
|
|
- printk(KERN_ERR "Bad IOCTL\n");
|
|
|
- break;
|
|
|
- case CYIO_CTL_LED_CMD:
|
|
|
- DBG("CYIO_CTL_LED_CMD arg[0x%03X]", arg);
|
|
|
-
|
|
|
- if ((arg & 0x2) && (arg & 0x1)) /* Power LED */
|
|
|
- {
|
|
|
- MSG("\n----------------> POWER LED ON\n");
|
|
|
- //GPH12
|
|
|
- __raw_writel(__raw_readl(S3C2410_GPHDAT) | (1 << 12), S3C2410_GPHDAT);
|
|
|
- }
|
|
|
- else if (arg & 0x2)
|
|
|
+ for (i = 0; i < CYEV_MAX_DEV; i++ )
|
|
|
{
|
|
|
- MSG("\n----------------> POWER LED OFF\n");
|
|
|
- __raw_writel(__raw_readl(S3C2410_GPHDAT) & ~(1 << 12), S3C2410_GPHDAT);
|
|
|
+ if ((DevList[i] != NULL) && (DevList[i]->ioctl != NULL))
|
|
|
+ {
|
|
|
+ if (GET_IOCTL_PREFIX(cmd) == DevList[i]->ioctl_prefix)
|
|
|
+ {
|
|
|
+ ret = DevList[i]->ioctl(cmd, arg);
|
|
|
+ /* if the ioctl called didn't return 0, try to see if there is
|
|
|
+ someone else for this one */
|
|
|
+ if (ret == 0)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if ((arg & 0x20) && (arg & 0x10)) /* Wifi LED */
|
|
|
+ printk(KERN_ERR "Bad IOCTL\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+// =============================================================================
|
|
|
+int CyEvent_RegisterDevice(cyevent_device *dev)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < CYEV_MAX_DEV; i++ )
|
|
|
+ {
|
|
|
+ if (DevList[i] == NULL)
|
|
|
{
|
|
|
- MSG("\n----------------> POWER WFI ON\n");
|
|
|
- //GPK8
|
|
|
- __raw_writel(__raw_readl(S3C2416_GPKDAT) | (1 << 8), S3C2416_GPKDAT);
|
|
|
+ DevList[i] = dev;
|
|
|
+ return 0;
|
|
|
}
|
|
|
- else if (arg & 0x20)
|
|
|
+ }
|
|
|
+
|
|
|
+ return -1; /* Too many devices... */
|
|
|
+}
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
+int CyEvent_DeregisterDevice(cyevent_device *dev)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < CYEV_MAX_DEV; i++ )
|
|
|
+ {
|
|
|
+ if (DevList[i] == dev)
|
|
|
{
|
|
|
- MSG("\n----------------> POWER WFI OFF\n");
|
|
|
- __raw_writel(__raw_readl(S3C2416_GPKDAT) & ~(1 << 8), S3C2416_GPKDAT);
|
|
|
+ DevList[i] = NULL;
|
|
|
+ return 0;
|
|
|
}
|
|
|
-
|
|
|
- if ((arg & 0x200) && (arg & 0x100)) /* Bluetooth LED */
|
|
|
+ }
|
|
|
+ return -1; /* Not found...*/
|
|
|
+}
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
+static void publish_read_event(unsigned char type)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < CYEV_MAX_DEV; i++ )
|
|
|
+ {
|
|
|
+ if ((DevList[i] != NULL) && (DevList[i]->event_read != NULL))
|
|
|
{
|
|
|
- MSG("\n----------------> POWER BTH ON\n");
|
|
|
- //GPK9
|
|
|
- __raw_writel(__raw_readl(S3C2416_GPKDAT) | (1 << 9), S3C2416_GPKDAT);
|
|
|
+ if ((DevList[i]->event_read_listen == 0) || (type == DevList[i]->event_read_listen))
|
|
|
+ DevList[i]->event_read(type);
|
|
|
}
|
|
|
- else if (arg & 0x200)
|
|
|
+ }
|
|
|
+}
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
+static void publish_empty_event(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < CYEV_MAX_DEV; i++ )
|
|
|
+ {
|
|
|
+ if ((DevList[i] != NULL) && (DevList[i]->event_listempty != NULL))
|
|
|
{
|
|
|
- MSG("\n----------------> POWER BTH OFF\n");
|
|
|
- __raw_writel(__raw_readl(S3C2416_GPKDAT) & ~(1 << 9), S3C2416_GPKDAT);
|
|
|
+ DevList[i]->event_listempty();
|
|
|
}
|
|
|
-
|
|
|
- ret = 0;
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case CYIO_CTL_USB_STATUS:
|
|
|
- value = gpio_get_value(S3C2410_GPG1);
|
|
|
-
|
|
|
- put_user(value, (unsigned long __user *)arg);
|
|
|
- ret = 0;
|
|
|
- break;
|
|
|
-
|
|
|
- case CYIO_CTL_SD_STATUS:
|
|
|
- value = gpio_get_value(S3C2410_GPF1);
|
|
|
-
|
|
|
- put_user(value, (unsigned long __user *)arg);
|
|
|
- ret = 0;
|
|
|
- break;
|
|
|
}
|
|
|
- return ret;
|
|
|
}
|
|
|
-// ===========================================================================
|
|
|
-static struct file_operations s_io_fops =
|
|
|
+// =============================================================================
|
|
|
+static struct file_operations s_ev_fops =
|
|
|
{
|
|
|
owner: THIS_MODULE,
|
|
|
read: ev_read,
|
|
@@ -410,7 +764,7 @@ static struct file_operations s_io_fops =
|
|
|
release: ev_release,
|
|
|
};
|
|
|
|
|
|
-gstatic struct miscdevice s_ev_dev =
|
|
|
+static struct miscdevice s_ev_dev =
|
|
|
{
|
|
|
.minor = 250,
|
|
|
.name = "cyio",
|
|
@@ -418,22 +772,38 @@ gstatic struct miscdevice s_ev_dev =
|
|
|
};
|
|
|
// ===========================================================================
|
|
|
// ---------------------------------------------------------------------------
|
|
|
-static int io_probe(struct platform_device *dev)
|
|
|
+static int ev_probe(struct platform_device *dev)
|
|
|
{
|
|
|
+ FUNC_IN();
|
|
|
+ FUNC_OUT();
|
|
|
return 0;
|
|
|
}
|
|
|
// ---------------------------------------------------------------------------
|
|
|
-static int io_remove(struct platform_device *dev)
|
|
|
+static int ev_remove(struct platform_device *dev)
|
|
|
{
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
misc_deregister(&s_ev_dev);
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
return 0;
|
|
|
}
|
|
|
// --------------------------------------------------------------------------
|
|
|
-static int io_resume(struct platform_device *dev)
|
|
|
+static int ev_suspend(struct platform_device *dev)
|
|
|
{
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+// --------------------------------------------------------------------------
|
|
|
+static int ev_resume(struct platform_device *dev)
|
|
|
+{
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
return 0;
|
|
|
}
|
|
|
-
|
|
|
// ---------------------------------------------------------------------------
|
|
|
static struct platform_driver cyev_driver =
|
|
|
{
|
|
@@ -444,28 +814,34 @@ static struct platform_driver cyev_driver =
|
|
|
},
|
|
|
.probe = ev_probe,
|
|
|
.remove = ev_remove,
|
|
|
- .suspend = NULL,
|
|
|
+ .suspend = NULL, //ev_suspend,
|
|
|
.resume = ev_resume,
|
|
|
};
|
|
|
// ---------------------------------------------------------------------------
|
|
|
// ===========================================================================
|
|
|
static int __init cyEv_init(void)
|
|
|
{
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
if (misc_register(&s_ev_dev))
|
|
|
return -EBUSY;
|
|
|
|
|
|
platform_driver_register(&cyev_driver);
|
|
|
|
|
|
+ FUNC_OUT();
|
|
|
return 0;
|
|
|
}
|
|
|
// ---------------------------------------------------------------------------
|
|
|
static void __exit cyEv_exit(void)
|
|
|
{
|
|
|
+ FUNC_IN();
|
|
|
+
|
|
|
platform_driver_unregister(&cyev_driver);
|
|
|
|
|
|
misc_deregister(&s_ev_dev);
|
|
|
+
|
|
|
+ FUNC_OUT();
|
|
|
}
|
|
|
-
|
|
|
// ---------------------------------------------------------------------------
|
|
|
module_init(cyEv_init);
|
|
|
module_exit(cyEv_exit);
|