Latest changes

This commit is contained in:
mlt
2010-07-26 13:16:12 +00:00
committed by Godzil
parent e3c7c1b8b5
commit db805e563c
15 changed files with 1561 additions and 1648 deletions

View File

@@ -24,6 +24,12 @@ config INPUT
if INPUT
config CYBOOK_EVENT_MANAGER
bool "Cybook Event Manager"
default y
---help---
Say Y if you use a Cybook 2416.
config INPUT_FF_MEMLESS
tristate "Support for memoryless force-feedback devices"
default n

View File

@@ -22,3 +22,4 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_CYBOOK_EVENT_MANAGER) += cyevent.o

View File

@@ -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 CYEV_MAX_EVENT 20
#define CYEV_REPEAT_DELAY (HZ/2); /* ~500ms */
#define CYEV_CURRENT_VERSION 0x10 /* 1.0 */
enum { INVALID = 0, VALID };
// =============================================================================
//#define DEBUG_MESSAGES
//#define DEBUG_TRACEFUNC
//#define VERBOSE_LEVEL INFO_DEBUG
struct
#define MODULE_NAME "CyEvent"
// =============================================================================
#define CYEV_MAX_EVENT 20
#define CYEV_MAX_DEV 5
#define CYEV_REPEAT_DELAY (HZ/2) /* ~500ms */
// =============================================================================
enum { INVALID = 0, VALID };
// =============================================================================
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,22 +450,39 @@ 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)
{
/* set the event "end of repeat" flag */
cyev_eventList[i].payload.flags |= CYEVENT_FLAG_ENDOFREPEAT;
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
{
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;
//FUNC_IN();
if (signal_pending(current))
{
ret = -ERESTARTSYS;
break;
}
}
if (CyEvent != NULL)
{
nRes = copy_to_user(buf, &CyEvent, nBytes);
if (!nRes)
nRes = nBytes;
}
if ( count < nBytes )
{
ret = -EINVAL;
goto exit;
}
return ret;
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:
for (i = 0; i < CYEV_MAX_DEV; i++ )
{
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;
}
}
}
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)
{
MSG("\n----------------> POWER LED OFF\n");
__raw_writel(__raw_readl(S3C2410_GPHDAT) & ~(1 << 12), S3C2410_GPHDAT);
}
if ((arg & 0x20) && (arg & 0x10)) /* Wifi LED */
{
MSG("\n----------------> POWER WFI ON\n");
//GPK8
__raw_writel(__raw_readl(S3C2416_GPKDAT) | (1 << 8), S3C2416_GPKDAT);
}
else if (arg & 0x20)
{
MSG("\n----------------> POWER WFI OFF\n");
__raw_writel(__raw_readl(S3C2416_GPKDAT) & ~(1 << 8), S3C2416_GPKDAT);
}
if ((arg & 0x200) && (arg & 0x100)) /* Bluetooth LED */
{
MSG("\n----------------> POWER BTH ON\n");
//GPK9
__raw_writel(__raw_readl(S3C2416_GPKDAT) | (1 << 9), S3C2416_GPKDAT);
}
else if (arg & 0x200)
{
MSG("\n----------------> POWER BTH OFF\n");
__raw_writel(__raw_readl(S3C2416_GPKDAT) & ~(1 << 9), S3C2416_GPKDAT);
}
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;
}
FUNC_OUT();
return ret;
}
// ===========================================================================
static struct file_operations s_io_fops =
// =============================================================================
int CyEvent_RegisterDevice(cyevent_device *dev)
{
int i;
for (i = 0; i < CYEV_MAX_DEV; i++ )
{
if (DevList[i] == NULL)
{
DevList[i] = dev;
return 0;
}
}
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)
{
DevList[i] = NULL;
return 0;
}
}
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))
{
if ((DevList[i]->event_read_listen == 0) || (type == DevList[i]->event_read_listen))
DevList[i]->event_read(type);
}
}
}
// -----------------------------------------------------------------------------
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))
{
DevList[i]->event_listempty();
}
}
}
// =============================================================================
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);

View File

@@ -231,6 +231,7 @@ config KEYBOARD_GPIO
config CYBOOK_CYIO
tristate "Cybook CyIO"
depends on CYBOOK_EVENT_MANAGER
# depends on MACH_CYBOOK_ORIZON
default y
help

File diff suppressed because it is too large Load Diff

View File

@@ -22,10 +22,10 @@
#include <cybook.h>
#include <linux/cyio.h>
#include <linux/cyevent.h>
#define DEBUG_MESSAGES
#define DEBUG_TRACEFUNC
//#define DEBUG_MESSAGES
//#define DEBUG_TRACEFUNC
//#define DBG_IRQ
#define MODULE_NAME "CYB_TILT"
@@ -209,7 +209,7 @@ static irqreturn_t orizontilt_interrupt(int irq, void *dev_id)
irqreturn_t ret = IRQ_HANDLED;
unsigned long tmpReg;
unsigned long calcTilt;
CyEvent_t event = NEW_CYEVENT(CYEVENT_TYPE_ORIENTATION);
FUNC_IN();
spin_lock(&suspendLock);
@@ -245,7 +245,8 @@ static irqreturn_t orizontilt_interrupt(int irq, void *dev_id)
{
MSG("Different from old one, push new event!");
OrizonTilt_CurrentDirection = calcTilt;
Cyio_PushEvent(CYEVENT_ORIENTATIONCHANGED, true);
event.data.orientation = calcTilt / 90;
CyEvent_PushOrUpdateUniqueEvent(&event, false);
}
spin_lock(&suspendLock);
@@ -370,7 +371,7 @@ static int __init orizontilt_init(void)
ioProcEntry->write_proc = orizontilt_procWriteIo;
ioProcEntry->owner = THIS_MODULE;
}
FUNC_OUT();
return 0;
}

View File

@@ -22,7 +22,7 @@
#include <linux/ctype.h>
#include <cybook.h>
#include <linux/cyio.h>
#include <linux/cyevent.h>
//#define DEBUG_MESSAGES
//#define DEBUG_TRACEFUNC
@@ -189,8 +189,7 @@ static Ots_PowerModes ots_currentPowerMode = POWER_UNDEFINED;
/****************************** i2c configuration *****************************/
#define OTS_ADDR_I2C 0x5C
static unsigned short normal_i2c[] = { OTS_ADDR_I2C,
I2C_CLIENT_END };
static unsigned short normal_i2c[] = { OTS_ADDR_I2C, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1 (ots);
@@ -295,7 +294,7 @@ static int ots_detect (struct i2c_adapter *adapter, int address, int kind)
goto exit_kfree;
}
ots_setPowerMode(POWER_ONAUTOSTANDBY);
ots_setPowerMode(POWER_ON/*AUTOSTANDBY*/);
ots_setDeviceParameters(INT_MODE, X_SENS, Y_SENS);
/* Now we are sure that the driver init successfully, then aquire the IRQ */
set_irq_type(IRQ_EINT2, IRQT_FALLING);
@@ -353,13 +352,19 @@ static int ots_resume (struct device *dev)
/******************************************************************************/
/********************** Interrupt Related functions ***************************/
/******************************************************************************/
static int oldX = 0, oldY = 0;
static int oldX1 = 0, oldY1 = 0;
static int oldX2 = 0, oldY2 = 0;
enum { FINGER_UP = 0, FINGER_MOVE, FINGER_DOWN };
static void ots_checkWorkFunction (struct work_struct *work)
{
unsigned long x1, y1, x2, y2;
FUNC_IN();
static int status = FINGER_UP;
CyEvent_t event = NEW_CYEVENT(CYEVENT_TYPE_TOUCH);
FUNC_IN();
/* Here do what the interrupt should... (ie read touch values) */
/* TODO: I reversed the X / Y axis to match old driver and revese the X value */
@@ -377,22 +382,57 @@ static void ots_checkWorkFunction (struct work_struct *work)
DBG("x1: %lu\ty1: %lu\tx2: %lu\ty2: %lu", x1, y1, x2, y2);
if ((x1 == 0) && (y1 == 0))
if ((x1 == 0) && (y1 == 0) && (x2 == 0) && (y2 == 0))
{ /* We assume that this is a finger up event */
if ( Cyio_PushEvent('R', 1) >= 0 )
if (status != FINGER_UP)
{
Cyio_PushEvent((oldX >> 8) & 0xFF, 0);
Cyio_PushEvent((oldX >> 0) & 0xFF, 0);
Cyio_PushEvent((oldY >> 8) & 0xFF, 0);
Cyio_PushEvent((oldY >> 0) & 0xFF, 0);
event.flags |= CYEVENT_FLAG_TOUCH_UP;
status = FINGER_UP;
}
else
goto exit; /* ignore the event */
}
else
{
oldX = 600 - x1;
oldY = y1;
oldX1 = 600 - x1;
oldY1 = y1;
if ((x2 != 0) || (y2 != 0))
{
oldX2 = 600 - x2;
oldY2 = y2;
event.data.touch.fingers = 2;
}
else
{
oldX2 = oldY2 = 0;
event.data.touch.fingers = 1;
}
if (status == FINGER_UP)
{
event.flags |= CYEVENT_FLAG_TOUCH_DOWN;
status = FINGER_DOWN;
}
else
{
event.flags |= CYEVENT_FLAG_TOUCH_MOVE;
status = FINGER_MOVE;
}
}
event.data.touch.x1 = oldX1;
event.data.touch.y1 = oldY1;
event.data.touch.x2 = oldX2;
event.data.touch.y2 = oldY2;
if (status == FINGER_UP)
oldX1 = oldY1 = oldX2 = oldY2 = 0;
CyEvent_PushOrUpdateUniqueEventFlaged(&event, false, CYEVENT_FLASH_TOUCH_MASK);
exit:
/* Say I get the data */
ots_ackInterrupt();
@@ -461,7 +501,7 @@ static void ots_setPowerMode (Ots_PowerModes power)
ots_setPowerMode(POWER_ON); /* Set myself as Power ON before anything */
//tmpReg = i2c_smbus_read_byte_data(ots_client, 0x24);
tmpReg = (((50) /* timeout in ms for auto sleep */ ) & 0x0F) << 4;
tmpReg = (((16) /* timeout in ms for auto sleep */ ) & 0x0F) << 4;
tmpReg |= (1<< 2); /* Activate auto sleep mode */
tmpReg |= 0x1; /* Set in "Sleep Mode" */
@@ -510,7 +550,7 @@ static void ots_setDeviceParameters (unsigned char int_mode,
tmpReg = i2c_smbus_read_byte_data(ots_client, 0xBE); // TEST
DBG("0xBE = %02X", tmpReg);
DBG("Firmware Version =0x%x\n", i2c_smbus_read_byte_data(ots_client, 0x77));
printk("TS Firmware Version = 0x%x\n", i2c_smbus_read_byte_data(ots_client, 0x77));
/* Activate the device ! */