diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c index 5bad750..2d5f8d0 100644 --- a/arch/arm/plat-s3c24xx/pm.c +++ b/arch/arm/plat-s3c24xx/pm.c @@ -907,7 +907,7 @@ static int s3c2410_pm_enter(suspend_state_t state) /* check if we have anything to wake-up with... bad things seem * to happen if you suspend with no wakeup (system will often * require a full power-cycle) - */ + */ if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { diff --git a/cybook.config b/cybook.config index 8d2cbef..312fa47 100644 --- a/cybook.config +++ b/cybook.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.21.5-cfs-v19 -# Mon May 24 20:53:14 2010 +# Mon Jun 28 18:41:53 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -602,6 +602,7 @@ CONFIG_SLHC=m # Input device support # CONFIG_INPUT=y +CONFIG_CYBOOK_EVENT_MANAGER=y # CONFIG_INPUT_FF_MEMLESS is not set # diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 9623231..aa6be1a 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -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 diff --git a/drivers/input/Makefile b/drivers/input/Makefile index da575de..dfec036 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -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 diff --git a/drivers/input/cyevent.c b/drivers/input/cyevent.c index bb28441..b8bf8df 100644 --- a/drivers/input/cyevent.c +++ b/drivers/input/cyevent.c @@ -1,6 +1,5 @@ -h // =========================================================================== -// cyio.c +// Cybook Event Manager - cyevent.c // Copyright (C) 2008-2010 Bookeen - All rights reserved // =========================================================================== #include @@ -14,132 +13,328 @@ h #include #include #include - +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include - #include -#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); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c26e04a..d741b15 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -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 diff --git a/drivers/input/keyboard/cyio.c b/drivers/input/keyboard/cyio.c index 189f799..ffee7f3 100644 --- a/drivers/input/keyboard/cyio.c +++ b/drivers/input/keyboard/cyio.c @@ -1,5 +1,5 @@ // =========================================================================== -// cyio.c +// Cybook Input Output - cyio.c // Copyright (C) 2008-2010 Bookeen - All rights reserved // =========================================================================== #include @@ -19,13 +19,7 @@ #include -#include - -#define CYIO_TIMER -//#define CYIO_REPEAT -//#define CYIO_POLLING - -//#define CYIO_ALTERNATE_KEY +#include //#define DEBUG_MESSAGES //#define DBG_IRQ @@ -43,45 +37,13 @@ #include #include "asm/io.h" - // =========================================================================== -spinlock_t io_lock = SPIN_LOCK_UNLOCKED; +#define IO_TIMER_DELAY_0500 ((HZ * 1) / 2) /* 500 ms */ +#define IO_TIMER_DELAY_2000 ((HZ * 2) / 1) /* 2 s */ +#define IO_TIMER_DELAY_1000 ((HZ * 1) / 1) /* 1 s */ -static unsigned long io_status = 0; -struct task_struct *ptsk = 0; - -#ifdef CYIO_POLLING -#define GPROCFS_ROOTFOLDER "cybook" -#define GPROCFS_MODULEFOLDER "gsensor" -#define GPROCFS_CALIBFILE "calibration" -#define GPROCFS_IOFILE "io" -#define GPROCFS_STATUSFILE "status" -#define GPROCFS_AXISFILE "axis" -#define GPROCFS_THDXFILE "thdx" -#define GPROCFS_THDYFILE "thdy" -#define GPROCFS_DIRECTIONFILE "direction" -#define GPROCFS_DEBUGFILE "debug" - -unsigned long tiltRotation; -static struct proc_dir_entry *rootDir, *ioProcEntry; -#endif - -#ifdef CYIO_TIMER -#define IO_TIMER_DELAY_1 ((HZ * 1) / 2) /* 500 ms */ -#define IO_TIMER_DELAY_2 ((HZ * 2) / 1) /* 2 s */ -#define IO_TIMER_DELAY_3 ((HZ * 1) / 1) /* 1 s */ static struct timer_list io_timer; -#ifdef CYIO_POLLING -static struct timer_list io_btn_timer; -#endif - -static int timer_inited = 0; -static int timer_run = 0; -#endif - -static volatile int CyIO_Running = 0; - #define TRUE (1==1) #define FALSE (0==1) @@ -89,52 +51,14 @@ static volatile int CyIO_Running = 0; typedef struct _cyIrq_ { - int nIrq; - u32 nGpio; - u8 bActive; - u8 bKeyIrq; // IRQ generated by a key? - u8 bIsAltKey; - u8 nCodeActive; // All interrupts generate a code when active - u8 nCodeInactive; // Some interrupts generate a code when inactive - u8 nCodeAlternate; - char* sName; -} cyIrq; - -#ifdef CYIO_POLLING -typedef struct _cyPoll_ -{ + int nIrq; u32 nGpio; - u8 oldState; - u8 nCodeActive; - u8 nCodeInactive; - char *sName; -} cyPoll; -#endif - -typedef struct _cyEvent_ -{ - u8 nCode; - u8 nKeyEvent; - u8 bValid; - void* pNext; -} cyEvent; - -static cyEvent s_nEvents[20]; -static int s_nEventMax = sizeof(s_nEvents)/sizeof(s_nEvents[0]); -static int s_nEventCnt = 0; -static int s_nKeyLogMax = 1; -static int s_nKeyLogCnt = 0; -static cyEvent* s_pEventR = 0; -static cyEvent* s_pEventW = 0; -#ifdef CYIO_REPEAT -static u8 s_nPrevKey = 0; -static u8 s_bRepMode = 0; -#endif -#ifdef CYIO_ALTERNATE_KEY -static u8 s_altKeyPress = 0; -static u32 s_altKeyGpio = 0; -static u8 s_altKeyPresent = FALSE; /* By default we don't have a Alt Key */ -#endif + u8 bActive; + u8 bAllowRepeat; // Allow Repeat? + u8 nCodeActive; // All interrupts generate a code when active + u8 nCodeInactive; // Some interrupts generate a code when inactive + char* sName; +} cyIrq; #define GPIO_F0 S3C2410_GPF0 #define GPIO_F1 S3C2410_GPF1 @@ -167,893 +91,212 @@ static u8 s_altKeyPresent = FALSE; /* By default we don't have a Alt Key */ #define GPIO_H4 S3C2410_GPH4 #define GPIO_H5 S3C2410_GPH5 -static cyIrq *s_nIrq ; +/* USB related */ +#define USBDETECT_GPIO GPIO_G1 +#define USBDETECT_EINT IRQ_EINT9 + static int nCnt; - -#ifdef CYIO_POLLING -static int nPCnt; -static cyPoll *s_nPio; -#endif - -static cyIrq s_nIrq_GEN4[] = -{ /* Event structure for the Cybook Gen3 (2440) */ - /* IRQ GPIO A B C Depress Event Release Event Alt Event Name Number */ - { IRQ_EINT0, GPIO_F0, 0, 1, 0, CYEVENT_KEY_OFF, 0, 0, "PowerBtn" } //0 - , { IRQ_EINT7, GPIO_F7, 0, 1, 0, CYEVENT_KEY_DOWN, 0, 0, "Down" } //1 - , { IRQ_EINT15, GPIO_G7, 0, 1, 0, CYEVENT_KEY_UP, 0, 0, "Up" } //2 - , { IRQ_EINT8, GPIO_G0, 0, 1, 0, CYEVENT_KEY_LEFT, 0, 0, "Left" } //3 - , { IRQ_EINT10, GPIO_G2, 0, 1, 0, CYEVENT_KEY_RIGHT, 0, 0, "Right" } //4 - , { IRQ_EINT14, GPIO_G6, 0, 1, 0, CYEVENT_KEY_ENTER, 0, 0, "Center" } //5 - , { IRQ_EINT9, GPIO_G1, 0, 0, 0, CYEVENT_USB_OUT, CYEVENT_USB_IN, 0, "USB" } //6 - /* IRQ GPIO A B C Depress Event Release Event Alt Event Name Number */ - /* A:Reserved (must be 0) - B: Is Keypress Event? (or Allow Repeat?) (1: Yes, 0: No) - C: Is Alt Key? (1: Yes 0: No) */ +static cyIrq s_nIrq[] ={ + /* IRQ GPIO A B Depress Event Release Event Name Number */ + { IRQ_EINT0, GPIO_F0, 0, 1, CYEVENT_KEY_OFF, 0, "PowerBtn" } //0 + , { IRQ_EINT7, GPIO_F7, 0, 1, CYEVENT_KEY_DOWN, 0, "Down" } //1 + , { IRQ_EINT15, GPIO_G7, 0, 1, CYEVENT_KEY_UP, 0, "Up" } //2 + , { IRQ_EINT8, GPIO_G0, 0, 1, CYEVENT_KEY_LEFT, 0, "Left" } //3 + , { IRQ_EINT10, GPIO_G2, 0, 1, CYEVENT_KEY_RIGHT, 0, "Right" } //4 + , { IRQ_EINT14, GPIO_G6, 0, 1, CYEVENT_KEY_ENTER, 0, "Center" } //5 + /* A:Reserved (must be 0) - B: Allow Repeat? (1: Yes, 0: No) */ }; -#ifdef CYIO_POLLING -static cyPoll s_nPoll_GEN4[] = +static irqreturn_t io_interrupt (int irq, void *dev_id); +static irqreturn_t io_usb_interrupt (int irq, void *dev_id); + +static void io_timer_handler (unsigned long nData); + +static void io_ev_emptylist(void); +static int io_ioctl(unsigned int cmd, unsigned long arg); +static void io_ev_read(unsigned char data); + +static struct cyevent_device cyio_cye_dev = { - /* GPIO, Must 0 Depress Event, Release Event Name */ - // { GPIO_H4, 0, CYEVENT_KEY_LEFT, 0, "Left" } - //, { GPIO_H5, 0, CYEVENT_KEY_RIGHT, 0, "Right" } - //, { GPIO_D14, 0, CYEVENT_KEY_ENTER, 0, "Enter" } - /* GPIO, Must 0 Depress Event, Release Event, Name */ + .deepsleep = NULL, + .suspend = NULL, + .resume = NULL, + .event_read = io_ev_read, + .ioctl = io_ioctl, + .ioctl_prefix = IOCTL_PFX('C'), + .event_listempty = io_ev_emptylist, + .event_read_listen = 0, }; -#endif - -static u8* s_pbUsbPowered = NULL; -static u8* s_pbPowerOff = NULL; -static u8* s_pbVolMinus = NULL; - -static irqreturn_t io_interrupt(int irq, void *dev_id); - -#ifdef CYIO_TIMER -static void io_timer_handler(unsigned long nData); -#ifdef CYIO_POLLING -static void io_btn_timer_handler(unsigned long nData); -#endif -#endif - -#ifdef CYIO_POLLING -static int procReadIo (char *page, char **start, off_t off, int count, - int *eof, void *data); -static int procWriteIo (struct file *file, const char *buffer, - unsigned long count, void *data); -#endif #undef MSG #undef DBG #ifdef DEBUG_MESSAGES -#define MSG(str) { printk(KERN_ERR str "\n"); } -#define DBG(str, ...) { printk(KERN_ERR str "\n", __VA_ARGS__); } +# define MSG(str) { printk(KERN_ERR str "\n"); } +# define DBG(str, ...) { printk(KERN_ERR str "\n", __VA_ARGS__); } #else -#define MSG(str) -#define DBG(str, ...) +# define MSG(str) +# define DBG(str, ...) #endif - -//#define DEBUG_SPINLOCK - -#ifdef DEBUG_SPINLOCK - -#define spinLock(spin) {\ - printk(KERN_ALERT ")))))))))))) (%s:%d) Wait for %p\n", __func__, __LINE__, spin);\ - spin_lock(spin); \ - printk(KERN_ALERT ")))))))))))) (%s:%d) Gain %p\n", __func__, __LINE__, spin);\ - } - -#define spinUnlock(spin) {\ - printk(KERN_ALERT ")))))))))))) (%s:%d) Free %p\n", __func__, __LINE__, spin);\ - spin_unlock(spin);\ - } - -#else - -#define spinLock(spin) spin_lock(spin) -#define spinUnlock(spin) spin_unlock(spin) - -#endif - -/* Allow other modules/driver to push cyio event */ -int Cyio_PushEvent(char eventId, char unique) -{ - cyEvent *pEventC; - int ret = 0; - - spinLock(&io_lock); - - /* CyIO is not running, ie no one take it, so don't accept events */ - if (CyIO_Running == 0) - { - spinUnlock(&io_lock); - return -1; - } - - if (unique != 0) - { - pEventC = s_pEventR; - do - { - if (pEventC->nCode == eventId) - { - ret = -EEXIST; - goto exit; - } - pEventC = pEventC->pNext; - } while ((pEventC != s_pEventW) && (s_pEventR != s_pEventW)); - } - DBG("New Pushed event '%c'\n", eventId>8); - - if (s_pEventW) - { - ++s_nEventCnt; - s_pEventW->nCode = eventId; - s_pEventW->nKeyEvent = 0; - s_pEventW->bValid = 1; - s_pEventW = s_pEventW->pNext; - } - spinUnlock(&io_lock); - ret = 0; -exit: - if (ptsk) - wake_up_process(ptsk); - - return ret; -} -EXPORT_SYMBOL(Cyio_PushEvent); - -#ifdef CYIO_TIMER -/* Allow other module/driver to reset the timer event */ -void Cyio_ResetTimer(void) -{ - if (timer_inited == 0) - return; - if (timer_run == 0) - return; -#ifndef ALTERNATE_TIMER_CHANGE - del_timer(&io_timer); - if (io_timer.data == CYEVENT_SUSPEND_SCREEN) - { - io_timer.expires = IO_TIMER_DELAY_1; - } - else //if (io_timer.data == CYEVENT_SUSPEND_DEVICE) - { - io_timer.expires = IO_TIMER_DELAY_2 - IO_TIMER_DELAY_1; - } - - io_timer.expires += jiffies; - add_timer(&io_timer); - timer_run = 1; -#else - //io_timer.expires += IO_TIMER_DELAY_3; - mod_timer(&io_timer, IO_TIMER_DELAY_3 + io_timer.expires); -#endif -} -EXPORT_SYMBOL(Cyio_ResetTimer); -#endif /* CYIO_TIMER */ - -// =========================================================================== -void io_initEventList(void) -{ - int i; - s_pEventR = 0; - s_nEventCnt = 0; - s_nKeyLogCnt = 0; - for (i=0; inCode = 0; - pEvent->nKeyEvent = 0; - pEvent->bValid = 0; - if (s_pEventR) - s_pEventR->pNext = pEvent; - s_pEventR = pEvent; - } - s_pEventR = &s_nEvents[0]; - s_nEvents[s_nEventMax-1].pNext = s_pEventR; - s_pEventW = s_pEventR; -#ifdef CYIO_REPEAT - s_nPrevKey = 0; - s_bRepMode = 0; -#endif -} // --------------------------------------------------------------------------- -u8 io_factoryPowerOff(void) -{ - return (s_pbPowerOff && - s_pbVolMinus && - (*s_pbPowerOff) && - (*s_pbVolMinus)) - ? 1 - : 0; -} -// --------------------------------------------------------------------------- -void io_initIrq(void) + +void io_initIrq (void) { + int i; + cyIrq *pIrq, *pIrq0; + int ret; - int i; - cyIrq *pIrq, *pIrq0; - int ret; -#ifdef CYIO_POLLING - cyPoll *pPoll, *pPoll0; - pPoll0 = &s_nPio[0]; -#endif - pIrq0 = &s_nIrq[0]; - + pIrq0 = &s_nIrq[0]; - DBG(">>%s()\n", __func__); - -#ifdef CYIO_POLLING - tiltRotation = 90; - for (i=0, pPoll=pPoll0; inGpio, 0); - s3c2410_gpio_pullup(pPoll->nGpio, 0); - } - s3c2410_gpio_cfgpin(GPIO_D10, 0); - s3c2410_gpio_pullup(GPIO_D10, 0); - s3c2410_gpio_cfgpin(GPIO_D11, 0); - s3c2410_gpio_pullup(GPIO_D11, 0); -#endif - // Read state as fast as possible (important when resuming) - for (i=0, pIrq=pIrq0; ibActive = !gpio_get_value(pIrq->nGpio); -#else - int j, nUp = 0; - for (j=0; j<4; ++j) - if (gpio_get_value(pIrq->nGpio)) - ++nUp; - pIrq->bActive = (nUp < 2); -#endif - } + DBG(">>%s()\n", __func__); - // Preparatory pass - for (i=0, pIrq=pIrq0; inCodeActive) - { - case CYEVENT_USB_IN: - case CYEVENT_USB_OUT: - s_pbUsbPowered = &pIrq->bActive; - break; - case CYEVENT_AC_IN: - break; - case CYEVENT_KEY_OFF: - s_pbPowerOff = &pIrq->bActive; - break; - case CYEVENT_KEY_VOLN: - s_pbVolMinus = &pIrq->bActive; - break; - } -#ifdef CYIO_ALTERNATE_KEY - if (pIrq->bIsAltKey) - { /* If this event is configured as the Alt key, just fill the needed variables */ - DBG("Found Alt key as '%s'\n", pIrq->sName); - s_altKeyPresent = TRUE; - s_altKeyGpio = pIrq->nGpio; - } -#endif - } - - if (io_factoryPowerOff()) - { // Special case - spinLock(&io_lock); - if (s_pEventW) - { - ++s_nEventCnt; - ++s_nKeyLogCnt; - s_pEventW->nCode = CYEVENT_FACTORY_OFF; - s_pEventW->nKeyEvent = 1; - s_pEventW->bValid = 0; - s_pEventW = s_pEventW->pNext; - } - spinUnlock(&io_lock); - } - else - { // Register events as if they had just occurred (esp. when resuming) - spinLock(&io_lock); - for (i=0, pIrq=pIrq0; ibActive && pIrq->bKeyIrq) - continue; - - if ((s_nEventMax <= s_nEventCnt) || - (pIrq->bKeyIrq && s_nKeyLogMax <= s_nKeyLogCnt)) - { - //break; - // !!! BUGBUG (we might miss system events once a key event is queued) - continue; - } - - if (s_pEventW) - { - ++s_nEventCnt; - if (pIrq->bKeyIrq) - ++s_nKeyLogCnt; - s_pEventW->nCode = pIrq->bActive ? pIrq->nCodeActive : pIrq->nCodeInactive; - s_pEventW->nKeyEvent = pIrq->bKeyIrq; - s_pEventW->bValid = 0; - s_pEventW = s_pEventW->pNext; - } - } - spinUnlock(&io_lock); - } - - for (i=0, pIrq=pIrq0; inIrq; set_irq_type(nIrq, IRQT_BOTHEDGE); - + /* Set no Pullup and no Pulldown */ s3c2410_gpio_pullup(pIrq->nGpio, 0); - - DBG(".. io_initIrq [%s][%c] bActive[%d]", pIrq->sName, pIrq->bActive || !pIrq->nCodeInactive ? (char)pIrq->nCodeActive : (char)pIrq->nCodeInactive, pIrq->bActive); - ret = request_irq(nIrq, io_interrupt, SA_INTERRUPT|SA_SHIRQ, pIrq->sName, pIrq); + + ret = request_irq(nIrq, io_interrupt, SA_INTERRUPT | SA_SHIRQ, pIrq->sName, pIrq); enable_irq_wake(nIrq); - if (ret != 0) + if ( ret != 0 ) { printk(KERN_ERR PFX "Error registering IRQ %d [%s]!\n", nIrq, pIrq->sName); } } -#ifdef CYIO_TIMER - init_timer(&io_timer); - timer_inited = 1; - io_timer.function = io_timer_handler; - io_timer.data = CYEVENT_SUSPEND_SCREEN; -#ifdef CYIO_POLLING - init_timer(&io_btn_timer); - io_btn_timer.function = io_btn_timer_handler; - io_btn_timer.expires = jiffies + HZ/8; - add_timer(&io_btn_timer); -#endif -#endif - spinLock(&io_lock); - CyIO_Running = 1; - spinUnlock(&io_lock); -} -// --------------------------------------------------------------------------- -void io_deinitIrq(void) -{ - int i; - cyIrq *pIrq, *pIrq0; - - spinLock(&io_lock); - CyIO_Running = 0; - spinUnlock(&io_lock); - -#ifdef CYIO_TIMER - del_timer(&io_timer); - timer_run = 0; -# ifdef CYIO_POLLING - del_timer(&io_btn_timer); -# endif -#endif - - //nCnt = sizeof(s_nIrq)/sizeof(s_nIrq[0]); - pIrq0 = &s_nIrq[0]; - for (i=0, pIrq=pIrq0; inIrq); - free_irq(pIrq->nIrq, pIrq); - } -} -// --------------------------------------------------------------------------- -static irqreturn_t io_interrupt(int irq, void *dev_id) -{ - cyIrq* pIrq = (cyIrq*)dev_id; - u8 bActive; - u8 blCodeActive; - unsigned long flags; - - spinlock_t lock = SPIN_LOCK_UNLOCKED; - -#ifdef CYIO_ALTERNATE_KEY - static int bAltKeyUsed = FALSE; -#endif - -#ifdef DBG_IRQ - static int s_nIrq_dbg = 0; - ++s_nIrq_dbg; -#endif - - spin_lock_irqsave(&lock, flags); - { // Avoid bounces - int i, nUp = 0; - for (i=0; i<10000; ++i) - if (gpio_get_value(pIrq->nGpio)) - ++nUp; - bActive = (nUp < 5000); - } - spin_unlock_irqrestore(&lock, flags); - - if (pIrq->bActive == bActive) - return IRQ_HANDLED; - -#ifdef DBG_IRQ -#ifdef CYIO_ALTERNATE_KEY - DBG(".. io_irq #%d [%s][%c] alt[%d:%d] bActive[%d]", s_nIrq_dbg, pIrq->sName, bActive || !pIrq->nCodeInactive ? (char)pIrq->nCodeActive : (char)pIrq->nCodeInactive, (s_altKeyPress && pIrq->bKeyIrq) ? pIrq->nCodeAlternate : (bActive ? pIrq->nCodeActive : pIrq->nCodeInactive), s_altKeyPress, bActive); -#else - DBG(".. io_irq #%d [%s][%c] bActive[%d]", s_nIrq_dbg, pIrq->sName, bActive || !pIrq->nCodeInactive ? (char)pIrq->nCodeActive : (char)pIrq->nCodeInactive, (bActive ? pIrq->nCodeActive : pIrq->nCodeInactive), bActive); -#endif -#endif - -#ifdef CYIO_ALTERNATE_KEY - blCodeActive = (s_altKeyPress && pIrq->bKeyIrq) ? pIrq->nCodeAlternate : (bActive ? pIrq->nCodeActive : pIrq->nCodeInactive); - if (s_altKeyPresent) - { - s_altKeyPress = !gpio_get_value(s_altKeyGpio); - DBG("alt status: %d", s_altKeyPress); - } -#else - blCodeActive = bActive ? pIrq->nCodeActive : pIrq->nCodeInactive; -#endif - - spinLock(&io_lock); - pIrq->bActive = bActive; - if (pIrq->bKeyIrq) - { - -#ifdef CYIO_REPEAT - DBG("bfr: s_nPrevKey = %d", s_nPrevKey); - if (s_nPrevKey) - { - DBG("s_nPrevKey is != 0 [%d]", s_nPrevKey); - - if (!pIrq->bActive /*|| s_nPrevKey != blCodeActive*/) - s_nPrevKey = 0; - - DBG("s_nPrevKey == %d (s_bRepMode:%d, pIrq->bActive:%d)", s_nPrevKey, s_bRepMode, pIrq->bActive); - - if (s_bRepMode && !s_nPrevKey) - { - MSG("Exit repeat mode..."); - s_bRepMode = 0; - if (s_pEventW) - { // NB: This is considered as a system event - ++s_nEventCnt; - s_pEventW->nCode = CYEVENT_KEY_REPEAT_END; - s_pEventW->nKeyEvent = 0; - s_pEventW->bValid = 0; - s_pEventW = s_pEventW->pNext; - } - if (ptsk) - wake_up_process(ptsk); - } - } -#endif -#ifdef CYIO_ALTERNATE_KEY - if ((!pIrq->bActive) && (pIrq->nGpio != s_altKeyGpio)) -#else - if (!pIrq->bActive) -#endif - { - spinUnlock(&io_lock); - MSG("Exiting IRQ Handler"); -#ifdef CYIO_KERNEL_2_4 - return; -#else - return IRQ_HANDLED; -#endif - } - } - spinUnlock(&io_lock); - -//#ifdef DBG_IRQ -// DBG(".. io_irq #%d [%s][%c] bActive[%d]", s_nIrq_dbg, pIrq->sName, bActive || !pIrq->nCodeInactive ? (char)pIrq->nCodeActive : (char)pIrq->nCodeInactive, bActive); -//#endif - - if (io_factoryPowerOff()) - { // Special case - spinLock(&io_lock); - MSG("Request Factory Setting...\n"); - if (s_pEventW) - { - ++s_nEventCnt; - ++s_nKeyLogCnt; - s_pEventW->nCode = CYEVENT_FACTORY_OFF; - s_pEventW->nKeyEvent = 1; - s_pEventW->bValid = 0; - s_pEventW = s_pEventW->pNext; - } - spinUnlock(&io_lock); - } - else - { - spinLock(&io_lock); - if ((s_nEventMax <= s_nEventCnt) || - (pIrq->bKeyIrq && s_nKeyLogMax <= s_nKeyLogCnt)) - { - spinUnlock(&io_lock); - DBG("s_nEventMax:%d, s_nEventCnt:%d, s_nKeyLogMax:%d, s_nKeyLogCnt:%d",s_nEventMax,s_nEventCnt,s_nKeyLogMax,s_nKeyLogCnt); - MSG("!!! Event list full !!!"); - return IRQ_HANDLED; - } - -#ifdef CYIO_ALTERNATE_KEY - - if (s_altKeyPresent && bAltKeyUsed && !s_altKeyPress && (pIrq->nGpio == s_altKeyGpio)) - { /* If the released key is the Alt Key and it was used as the Alt Key, do not send an event */ - MSG("Alt Key released... Do Nothing"); - bAltKeyUsed = FALSE; - s_nPrevKey = 0; - spinUnlock(&io_lock); - return IRQ_HANDLED; - } - if (s_altKeyPresent && (pIrq->nGpio == s_altKeyGpio)) - { /* If the altKey is pressed, we have to do a little trick: Inverse it's active state */ - MSG("Alt key event..."); - /* To be sure */ - s_nPrevKey = 0; - s_bRepMode = 0; - - bActive = !bActive; - } - else if (s_altKeyPresent && s_altKeyPress && pIrq->bKeyIrq) - {/* The event is a keypress and the AltKey is pressed, set our internal value to prevent Alt to send an event */ - MSG("Button press with Alt..."); - if (pIrq->nCodeAlternate != 0) - bAltKeyUsed = TRUE; - } - MSG("Hum..."); -#endif - - if (s_pEventW) - { - MSG("Will push another event..."); - ++s_nEventCnt; - if (pIrq->bKeyIrq) - ++s_nKeyLogCnt; - -#ifdef CYIO_ALTERNATE_KEY - s_pEventW->nCode = (s_altKeyPress && pIrq->bKeyIrq) ? pIrq->nCodeAlternate : (bActive ? pIrq->nCodeActive : pIrq->nCodeInactive); -#else - s_pEventW->nCode = bActive ? pIrq->nCodeActive : pIrq->nCodeInactive; -#endif - - s_pEventW->nKeyEvent = pIrq->bKeyIrq; - s_pEventW->bValid = 0; - - s_pEventW = s_pEventW->pNext; - } - spinUnlock(&io_lock); - } - - if (ptsk) - wake_up_process(ptsk); - - return IRQ_HANDLED; -} - - -// --------------------------------------------------------------------------- -#ifdef CYIO_TIMER -#ifdef CYIO_POLLING -static void io_btn_timer_handler(unsigned long nData) -{ - /* read buttons */ - cyPoll *pPoll, *pPoll0; - int i; - int curState; - int currentTilt, tE1, tE2; - pPoll0 = &s_nPio[0]; - - DBG(">>%s()\n", __func__); - - for (i=0, pPoll=pPoll0; inGpio); - DBG("|| Btn '%s' [current: %d, old: %d, gpio: %d]\n", pPoll->sName, curState, pPoll->oldState, pPoll->nGpio); - /* If button found pressed, then push event 'bout them */ - if (pPoll->oldState != curState) - { - if (curState != 0) - Cyio_PushEvent(pPoll->nCodeActive, 1); - /*else - Cyio_PushEvent(CYEVENT_KEY_REPEAT_END, 1);*/ - } - else if (pPoll->oldState != 0) - { - /* Push event with repeat flag */ - //Cyio_PushEvent(pPoll->nCodeActive | CYEVENT_KEY_REPEAT_FLAG, 1); - } - - pPoll->oldState = curState; - - } - - /* special case, look at the tilt sensor */ - tE1 = !gpio_get_value(GPIO_D11); - tE2 = !gpio_get_value(GPIO_D10); - currentTilt = 0; - if (!tE2) - currentTilt |= 1 << 1; - if (!tE1) - currentTilt |= 1 << 0; - - switch(currentTilt) + /* Setup USB irq */ + set_irq_type(USBDETECT_EINT, IRQT_BOTHEDGE); + s3c2410_gpio_pullup(USBDETECT_GPIO, 0); + ret = request_irq(USBDETECT_EINT, io_usb_interrupt, SA_INTERRUPT | SA_SHIRQ, "USB Detect", &nCnt); + enable_irq_wake(USBDETECT_EINT); + if (ret != 0) { - case 0x00: /* 90 */ - currentTilt = 90; - break; - - case 0x01: /* 0 */ - currentTilt = 0; - break; - - case 0x02: /* 180 */ - currentTilt = 180; - break; - - case 0x03: /* 270 */ - currentTilt = 270; - break; - } - if (currentTilt != tiltRotation) - { /* We move */ - tiltRotation = currentTilt; - printk("New tilt: %d\n", tiltRotation); - Cyio_PushEvent(CYEVENT_ORIENTATIONCHANGED, 1); + printk(KERN_ERR PFX "Error registering USB Detect IRQ!\n"); } + + init_timer(&io_timer); + io_timer.function = io_timer_handler; + io_timer.data = CYEVENT_TIMER_SCREEN; +} +// ----------------------------------------------------------------------------- +static void io_timer_handler (unsigned long nData) +{ + CyEvent_t event = NEW_CYEVENT(CYEVENT_TYPE_TIMER); + + DBG("Timer [%ld] tick...\n", nData); + + del_timer(&io_timer); + event.data.timer_type = nData; - /* Update the timer */ - io_btn_timer.expires = jiffies + HZ/8; - mod_timer(&io_btn_timer, io_btn_timer.expires); - DBG("<<%s()\n", __func__); + CyEvent_PushNewUniqueEvent(&event); } -#endif -static void io_timer_handler(unsigned long nData) +// ----------------------------------------------------------------------------- +void io_deinitIrq (void) { - DBG("Timer [%ld] tick...\n", nData); + int i; + cyIrq *pIrq, *pIrq0; - spin_lock_irq(&io_lock); + del_timer(&io_timer); - del_timer(&io_timer); - timer_run = 0; - if (s_nEventCnt < s_nEventMax) - { - if (s_pEventW) - { - ++s_nEventCnt; - s_pEventW->nCode = (u8)nData; - s_pEventW->nKeyEvent = 0; - s_pEventW->bValid = 0; - s_pEventW = s_pEventW->pNext; - } - } - - spin_unlock_irq(&io_lock); - - if (ptsk) - wake_up_process(ptsk); -//end_timer: - return; -} -#endif - -// =========================================================================== -static int io_open(struct inode *inode, struct file *file) -{ - //MSG(">> io_open"); - - //spin_lock_irq(&io_lock); - spinLock(&io_lock); - - if (io_status) - { - //spin_unlock_irq(&io_lock); - spinUnlock(&io_lock); - //MSG(".. io_open !!! Busy"); - return -EBUSY; - } - - io_status = 1; - - //spin_unlock_irq(&io_lock); - spinUnlock(&io_lock); - - io_initIrq(); - - return 0; -} -// --------------------------------------------------------------------------- -static int io_release(struct inode *inode, struct file *file) -{ - MSG(">> io_release"); - - io_deinitIrq(); - - spin_lock_irq(&io_lock); - - io_status = 0; - - // The driver is likely to be closed & reopened within suspend sequences - // Only initialize the list when registering the driver and when closing it - // This allows for a quicker opening of the driver - io_initEventList(); - - spin_unlock_irq(&io_lock); - - MSG("<< io_release"); - return 0; -} -// --------------------------------------------------------------------------- -ssize_t io_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - int nBytes = sizeof(unsigned long); - unsigned long nData; - ssize_t nRes = 0; - u8 bDataValid = 0; - if (count < sizeof(unsigned long)) - return -EINVAL; - - while (1) - { - //spin_lock_irq(&io_lock); - spinLock(&io_lock); - nData = 0; - if (s_nEventCnt) - { - nData = s_pEventR->nCode; - bDataValid = s_pEventR->bValid; - s_pEventR->nCode = 0; - --s_nEventCnt; - if (s_pEventR->nKeyEvent) - { - --s_nKeyLogCnt; -#ifdef CYIO_REPEAT - if (nData != CYEVENT_KEY_OFF) - { - s_nPrevKey = nData; - s_bRepMode = 0; - } -#endif - } - s_pEventR = s_pEventR->pNext; - } -#ifdef CYIO_REPEAT - if (!nData && s_nPrevKey) - { // Check new status - int i; - cyIrq *pIrq, *pIrq0; - - pIrq0 = &s_nIrq[0]; - for (i=0, pIrq=pIrq0; inCodeActive != s_nPrevKey) && (pIrq->nCodeAlternate != s_nPrevKey)) -#else - if (pIrq->nCodeActive != s_nPrevKey) -#endif + pIrq0 = &s_nIrq[0]; + for ( i = 0, pIrq = pIrq0; i < nCnt; ++i, ++pIrq ) { - continue; + disable_irq_wake(pIrq->nIrq); + free_irq(pIrq->nIrq, pIrq); } - if (!pIrq->bActive || gpio_get_value(pIrq->nGpio)) - { - s_nPrevKey = 0; - } - break; - } - if (s_nPrevKey) - { - nData = s_nPrevKey | CYEVENT_KEY_REPEAT_FLAG; - s_bRepMode = 1; - } - } -#endif - spinUnlock(&io_lock); - - if ((nData != 0) | (bDataValid == 1)) - { -#ifdef CYIO_TIMER - del_timer(&io_timer); - timer_run = 0; - io_timer.data = (nData == CYEVENT_SUSPEND_SCREEN) ? CYEVENT_SUSPEND_DEVICE : CYEVENT_SUSPEND_SCREEN; -#endif - break; - } - -#ifdef CYIO_TIMER - if (s_pbUsbPowered && (*s_pbUsbPowered)) - { - del_timer(&io_timer); - timer_run = 0; - if (io_timer.data == CYEVENT_SUSPEND_SCREEN) - { - io_timer.expires = IO_TIMER_DELAY_1; - io_timer.expires += jiffies; - add_timer(&io_timer); - } - else //if (io_timer.data == CYEVENT_SUSPEND_DEVICE) - { - io_timer.expires = IO_TIMER_DELAY_2 - IO_TIMER_DELAY_1; - io_timer.expires += jiffies; - add_timer(&io_timer); - } - timer_run = 1; - } -#endif - - ptsk = current; - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - set_current_state(TASK_RUNNING); - ptsk = 0; - - if (signal_pending(current)) - { - nRes = -ERESTARTSYS; - break; - } - } - - if ((nData != 0) | (bDataValid == 1)) - { - nRes = copy_to_user(buf,&nData,nBytes); - if (!nRes) - nRes = nBytes; - } - - return nRes; + disable_irq_wake(USBDETECT_EINT); + free_irq(USBDETECT_EINT, &nCnt); } -// --------------------------------------------------------------------------- -static int io_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +// ----------------------------------------------------------------------------- +static int is_usb_plugged(void) +{ + int i, nUp = 0; + + for ( i = 0; i < 5000; ++i ) + if ( gpio_get_value(USBDETECT_GPIO) ) + ++nUp; + return nUp > 2500; +} +// ----------------------------------------------------------------------------- +static void io_ev_emptylist(void) +{ + /* If we are powered, don't use timers... */ + if (!is_usb_plugged()) + { + del_timer(&io_timer); + if (io_timer.data == CYEVENT_TIMER_SCREEN) + { + io_timer.expires = IO_TIMER_DELAY_0500; + io_timer.expires += jiffies; + add_timer(&io_timer); + } + else //if (io_timer.data == CYEVENT_TIMER_DEVICE) + { + io_timer.expires = IO_TIMER_DELAY_2000 - IO_TIMER_DELAY_0500; + io_timer.expires += jiffies; + add_timer(&io_timer); + } + } +} +// ----------------------------------------------------------------------------- +static void io_ev_read(unsigned char type) +{ + del_timer(&io_timer); + + if (type != CYEVENT_TYPE_TIMER) + io_timer.data = CYEVENT_TIMER_SCREEN; + else + io_timer.data = (io_timer.data == CYEVENT_TIMER_SCREEN)?CYEVENT_TIMER_DEVICE:CYEVENT_TIMER_SCREEN; +} +// ----------------------------------------------------------------------------- +static int io_ioctl(unsigned int cmd, unsigned long arg) { int ret = -EINVAL; unsigned long value; + int i; + ret = -EINVAL; + switch(cmd) { - default: - printk(KERN_ERR "Bad IOCTL\n"); - ret = 0x42; - break; - - case CYIO_CTL_LED_CMD: - DBG("CYIO_CTL_LED_CMD arg[0x%03X]", arg); + case CYIO_CTL_LED_CMD: 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); @@ -1069,197 +312,104 @@ static int io_ioctl(struct inode *inode, struct file *file, break; } - return ret; + return ret; +} +// ----------------------------------------------------------------------------- +static irqreturn_t io_usb_interrupt (int irq, void *dev_id) +{ + CyEvent_t event = NEW_CYEVENT(CYEVENT_TYPE_SYSTEM); + + + event.flags |= CYEVENT_FLAG_USB_MESSAGE; + + if (is_usb_plugged()) + { + event.flags |= CYEVENT_FLAG_SYS_STATUS; + } + + CyEvent_PushNewEvent(&event, false); + + return IRQ_HANDLED; +} +// ----------------------------------------------------------------------------- +static irqreturn_t io_interrupt (int irq, void *dev_id) +{ + u8 bActive; + u8 blCodeActive; + unsigned long flags; + CyEvent_t event = NEW_CYEVENT(CYEVENT_TYPE_KEY); + cyIrq* pIrq = (cyIrq*)dev_id; + + spinlock_t lock = SPIN_LOCK_UNLOCKED; + +#ifdef DBG_IRQ + static int s_nIrq_dbg = 0; + ++s_nIrq_dbg; +#endif + + /* Prevent bouncing... */ + spin_lock_irqsave(&lock, flags); + { // Avoid bounces + int i, nUp = 0; + for ( i = 0; i < 10000; ++i ) + if ( gpio_get_value(pIrq->nGpio) ) + ++nUp; + bActive = (nUp < 5000); + } + spin_unlock_irqrestore(&lock, flags); + + if ( pIrq->bActive == bActive ) + return IRQ_HANDLED; + + pIrq->bActive = bActive; + +#ifdef DBG_IRQ + DBG(".. io_irq #%d [%s][%c] bActive[%d]", s_nIrq_dbg, pIrq->sName, bActive || !pIrq->nCodeInactive ? (char)pIrq->nCodeActive : (char)pIrq->nCodeInactive, (bActive ? pIrq->nCodeActive : pIrq->nCodeInactive), bActive); +#endif + + blCodeActive = bActive ? pIrq->nCodeActive : pIrq->nCodeInactive; + + event.data.key = blCodeActive; + event.flags |= CYEVENT_FLAG_KEY_CONTROL_CHARS; + + DBG("blCodeActive: %d", blCodeActive); + if ( blCodeActive == 0 ) + { + CyEvent_InvalidateRepeatableEvent(&event); + } + else + { + if ( pIrq->bAllowRepeat ) + CyEvent_PushNewEvent(&event, true); + else + CyEvent_PushNewUniqueEvent(&event); + } + + return IRQ_HANDLED; } // =========================================================================== -static struct file_operations s_io_fops = +static int __init cyIo_init (void) { - owner: THIS_MODULE, - read: io_read, - ioctl: io_ioctl, - open: io_open, - release: io_release, -}; + nCnt = sizeof (s_nIrq) / sizeof (s_nIrq[0]); -static struct miscdevice s_io_dev = -{ - .minor = 250, - .name = "cyio", - .fops = &s_io_fops, -}; -// =========================================================================== -// --------------------------------------------------------------------------- -static int io_probe(struct platform_device *dev) -{ - return 0; -} -// --------------------------------------------------------------------------- -static int io_remove(struct platform_device *dev) -{ - misc_deregister(&s_io_dev); - return 0; -} -// -------------------------------------------------------------------------- -static int io_resume(struct platform_device *dev) -{ - //cyIrq *pIrq; - //u8 bSdCd; - MSG(">>Resume() .......\n"); -#if 0 - if ((platform_type == CYBOOK_GEN3) || (platform_type == CYBOOK_GEN3GOLD)) - { - pIrq = &s_nIrq[13]; - } - else - { - pIrq = &s_nIrq[11]; - } - - bSdCd = !read_gpio_bit(pIrq->nGpio); - - //MSG(">>Resume() .......bSdCd 0x%x\n",bSdCd); - if (pIrq->bActive == bSdCd) + io_initIrq(); + CyEvent_RegisterDevice(&cyio_cye_dev); return 0; - - spinLock(&io_lock); - pIrq->bActive = bSdCd; - if (s_pEventW) - { - ++s_nEventCnt; - s_pEventW->nCode = pIrq->bActive ? pIrq->nCodeActive : pIrq->nCodeInactive; - s_pEventW->nKeyEvent = pIrq->bKeyIrq; - s_pEventW = s_pEventW->pNext; - } - spinUnlock(&io_lock); - if (ptsk) - wake_up_process(ptsk); -#endif - - MSG("<read_proc = procReadIo; - ioProcEntry->write_proc = procWriteIo; - ioProcEntry->owner = THIS_MODULE; -#endif - - io_initEventList(); - - if (misc_register(&s_io_dev)) - return -EBUSY; - - platform_driver_register(&cyio_driver); - - return 0; -} -// --------------------------------------------------------------------------- -static void __exit cyIo_exit(void) -{ - platform_driver_unregister(&cyio_driver); - - misc_deregister(&s_io_dev); - - //MSG("<< cyIo_exit"); -} - -#ifdef CYIO_POLLING -static int procReadIo (char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int len; - char tmp = 0; - //printk("Read IO Tilt [%d]", tiltRotation); - switch (tiltRotation) - { - case 270: - tmp++; - case 180: - tmp++; - case 90: - tmp++; - default: - break; - } - - len = sprintf (page, "%02X", tmp); - DBG("io readed value: %02X", tmp); - return len; -} - -static int procWriteIo (struct file *file, const char *buffer, - unsigned long count, void *data) -{ - char cmd; - /* in case of... */ - if ( count < 1 ) - return 0; - - cmd = buffer[0]; - switch(cmd) - { - case G_SENSOR_CAL: - case G_SENSOR_ON: - case G_SENSOR_OFF: - case 254: - break; - - default: - printk(KERN_ERR "ProcIO: Unknown command '%c'\n",cmd); - break; - } - - return count; -} -#endif - -// --------------------------------------------------------------------------- -module_init(cyIo_init); -module_exit(cyIo_exit); -// --------------------------------------------------------------------------- -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Bookeen "); -MODULE_DESCRIPTION("Cybook IO Manager"); -MODULE_VERSION("3.0"); +module_init (cyIo_init); +module_exit (cyIo_exit); +// --------------------------------------------------------------------------- +MODULE_LICENSE ("BPL (Bookeen Private Licence)"); +MODULE_AUTHOR ("Bookeen "); +MODULE_DESCRIPTION ("Cybook IO Manager"); +MODULE_VERSION ("3.0"); // =========================================================================== diff --git a/drivers/input/misc/orizon_tilt.c b/drivers/input/misc/orizon_tilt.c index ffeaa57..1e95119 100644 --- a/drivers/input/misc/orizon_tilt.c +++ b/drivers/input/misc/orizon_tilt.c @@ -22,10 +22,10 @@ #include -#include +#include -#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; } diff --git a/drivers/input/touchscreen/orizon_ts.c b/drivers/input/touchscreen/orizon_ts.c index e130a35..a268236 100644 --- a/drivers/input/touchscreen/orizon_ts.c +++ b/drivers/input/touchscreen/orizon_ts.c @@ -22,7 +22,7 @@ #include #include -#include +#include //#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 ! */ diff --git a/drivers/mmc/host/s3c-hsmmc.c b/drivers/mmc/host/s3c-hsmmc.c index d6bbc74..519c6fc 100644 --- a/drivers/mmc/host/s3c-hsmmc.c +++ b/drivers/mmc/host/s3c-hsmmc.c @@ -55,6 +55,8 @@ #include +#include + /*Qisda , wenny cheng , 20091224 , board id info {*/ #include <../include/asm-arm/plat-s3c24xx/common-smdk.h> /*Qisda , wenny cheng , 20091224 , board id info }*/ @@ -1103,15 +1105,12 @@ out: return result; } - -#include -int Cyio_PushEvent(char eventId, char unique); - static irqreturn_t s3c_hsmmc_irq_cd (int irq, void *dev_id) { struct s3c_hsmmc_host *host = dev_id; int ext_CD_int = 0; - + CyEvent_t CyEvent = NEW_CYEVENT(CYEVENT_TYPE_SYSTEM); + CyEvent.flags |= CYEVENT_FLAG_SD_MESSAGE; #if defined(CONFIG_CPU_S3C2450) || defined(CONFIG_CPU_S3C2416) ext_CD_int = readl(S3C2410_GPFDAT); ext_CD_int &= 0x2; /* GPF1 */ @@ -1120,7 +1119,8 @@ static irqreturn_t s3c_hsmmc_irq_cd (int irq, void *dev_id) ext_CD_int &= 0x2000; /* GPN13 */ #endif //printk("\ns3c_hsmmc_irq_cd, ext_CD_int: %d, card_detect: %d, card_detect2: %d\n", ext_CD_int, card_detect, card_detect2); - if(ext_CD_int && card_detect) { + if(ext_CD_int && card_detect) + { printk("s3c-hsmmc channel-0(EXT): card removed.\n"); /*Qisda Qube for sd card detect20091124*/ //set_irq_type(host->irq_cd, IRQT_FALLING); @@ -1133,10 +1133,12 @@ static irqreturn_t s3c_hsmmc_irq_cd (int irq, void *dev_id) card_detect2 = 2; /* Send CyIO event */ - Cyio_PushEvent(CYEVENT_SD_OUT, 1); + /* SD OUT */ + CyEvent_PushNewUniqueEvent(&CyEvent); } - else if(!ext_CD_int && !card_detect) { + else if(!ext_CD_int && !card_detect) + { printk("s3c-hsmmc channel-0(EXT): card inserted.\n"); /*Qisda Qube for sd card detect20091124*/ //set_irq_type(host->irq_cd, IRQT_RISING); @@ -1156,7 +1158,9 @@ static irqreturn_t s3c_hsmmc_irq_cd (int irq, void *dev_id) } /* Send CyIO event */ - Cyio_PushEvent(CYEVENT_SD_IN, 1); + /* SD IN */ + CyEvent.flags |= CYEVENT_FLAG_SYS_STATUS; + CyEvent_PushNewUniqueEvent(&CyEvent); } //Qisda, Asaku Chen, 2009/11/03 { diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index c7097ed..5046bae 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -276,8 +276,8 @@ MODULE_LICENSE("Dual BSD/GPL"); * * DO NOT REUSE THESE IDs with any other driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ -#define DRIVER_VENDOR_ID 0x0525 // NetChip -#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget +#define DRIVER_VENDOR_ID 0x0525 // NetChip +#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget /* @@ -286,9 +286,17 @@ MODULE_LICENSE("Dual BSD/GPL"); * and endpoint addresses. */ +//#define DEBUG +//#define VERBOSE /*-------------------------------------------------------------------------*/ +#if 0 +#undef dev_printk +#define dev_printk(level, l, fmt, args...) \ + printk(KERN_DEBUG DRIVER_NAME ": " fmt, ## args) +#endif + #define xprintk(f,level,fmt,args...) \ dev_printk(level , &(f)->gadget->dev , fmt , ## args) #define yprintk(l,level,fmt,args...) \ @@ -358,7 +366,8 @@ static struct { int removable; int can_stall; - + int hw_disk_status; + char *transport_parm; char *protocol_parm; unsigned short vendor; @@ -373,18 +382,19 @@ static struct { char *protocol_name; } mod_data = { // Default values - .transport_parm = "BBB", + .transport_parm = "BBB", .protocol_parm = "SCSI", .removable = 0, .can_stall = 1, .vendor = DRIVER_VENDOR_ID, - .product = DRIVER_PRODUCT_ID, - .release = 0xffff, // Use controller chip type + .product = DRIVER_PRODUCT_ID, + .release = 0xffff, // Use controller chip type .buflen = 16384, .serial = "CYBOR10", }; - +#undef S_IRUGO +#define S_IRUGO (0644) module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, S_IRUGO); MODULE_PARM_DESC(file, "names of backing files or devices"); @@ -404,6 +414,14 @@ MODULE_PARM_DESC(removable, "true to simulate removable media"); module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); +module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); +MODULE_PARM_DESC(vendor, "USB Vendor ID"); + +module_param_named(product, mod_data.product, ushort, S_IRUGO); +MODULE_PARM_DESC(product, "USB Product ID"); + +module_param_named(serial, mod_data.serial, charp, S_IRUGO); +MODULE_PARM_DESC(serial, "Device serial number"); /* In the non-TEST version, only the module parameters listed above * are available. */ @@ -416,21 +434,12 @@ module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " "8070, or SCSI)"); -module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); -MODULE_PARM_DESC(vendor, "USB Vendor ID"); - -module_param_named(product, mod_data.product, ushort, S_IRUGO); -MODULE_PARM_DESC(product, "USB Product ID"); - module_param_named(release, mod_data.release, ushort, S_IRUGO); MODULE_PARM_DESC(release, "USB release number"); module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); MODULE_PARM_DESC(buflen, "I/O buffer size"); -module_param_named(serial, mod_data.serial, charp, S_IRUGO); -MODULE_PARM_DESC(serial, "Device serial number"); - #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -2072,12 +2081,9 @@ static int do_verify(struct fsg_dev *fsg) static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) { u8 *buf = (u8 *) bh->buf; -/* Qisda, howard.hsu, 2010/01/26, change usb device name { */ - //static char vendor_id[] = "Linux "; - //static char product_id[] = "File-Stor Gadget"; static char vendor_id[] = "Bookeen "; static char product_id[] = "Cybook Orizon"; -/* } Qisda, howard.hsu, 2010/01/26, change usb device name */ + if (!fsg->curlun) { // Unsupported LUNs are okay fsg->bad_lun_okay = 1; memset(buf, 0, 36); @@ -2263,7 +2269,6 @@ static int do_start_stop(struct fsg_dev *fsg) loej = fsg->cmnd[4] & 0x02; start = fsg->cmnd[4] & 0x01; -#ifdef CONFIG_USB_FILE_STORAGE_TEST if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start curlun->sense_data = SS_INVALID_FIELD_IN_CDB; @@ -2273,11 +2278,13 @@ static int do_start_stop(struct fsg_dev *fsg) if (!start) { /* Are we allowed to unload the media? */ - if (curlun->prevent_medium_removal) { +#if 0 /* We can't prevent hardware removal */ + if (curlun->prevent_medium_removal) { LDBG(curlun, "unload attempt prevented\n"); curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; return -EINVAL; } +#endif if (loej) { // Simulate an unload/eject up_read(&fsg->filesem); down_write(&fsg->filesem); @@ -2294,11 +2301,10 @@ static int do_start_stop(struct fsg_dev *fsg) return -EINVAL; } } -#endif + return 0; } - static int do_prevent_allow(struct fsg_dev *fsg) { struct lun *curlun = fsg->curlun; @@ -3682,11 +3688,13 @@ static ssize_t store_file(struct device *dev, struct device_attribute *attr, con struct fsg_dev *fsg = dev_get_drvdata(dev); int rc = 0; - if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { - LDBG(curlun, "eject attempt prevented\n"); - return -EBUSY; // "Door is locked" - } - +#if 0 /* Current hardware can't prevent remove */ + if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { + LDBG(curlun, "eject attempt prevented\n"); + return -EBUSY; // "Door is locked" + } /* If file[] is NULL, then the media has been physically removed, we can't allow access to it */ +#endif + LDBG(curlun, "Will try to mount floppy [%p] '%s'\n", buf, buf); /* Remove a trailing newline */ if (count > 0 && buf[count-1] == '\n') ((char *) buf)[count-1] = 0; // Ugh! @@ -3694,12 +3702,14 @@ static ssize_t store_file(struct device *dev, struct device_attribute *attr, con /* Eject current medium */ down_write(&fsg->filesem); if (backing_file_is_open(curlun)) { + LDBG(curlun, "There is currently a floppy.. Eject it before...\n"); close_backing_file(curlun); curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; } /* Load new medium */ if (count > 0 && buf[0]) { + LDBG(curlun, "File name is valide, now insert floppy...\n"); rc = open_backing_file(curlun, buf); if (rc == 0) curlun->unit_attention_data = @@ -3889,7 +3899,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) goto out; if (mod_data.removable) { // Enable the store_xxx attributes - dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644; + dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0664; dev_attr_status.attr.mode = 0444; dev_attr_ro.store = store_ro; dev_attr_file.store = store_file; diff --git a/drivers/video/epaper.c b/drivers/video/epaper.c index fc74238..a5b40fb 100644 --- a/drivers/video/epaper.c +++ b/drivers/video/epaper.c @@ -901,8 +901,6 @@ static inline void s3c2416_i80_write(int data) tmp |= SYS_WR_CON; __raw_writel(tmp, rSIFCCON0); - if ( !tcon_inPortraitMode ) - tcon_ndelay(25); __raw_writel(data, rSIFCCON1); //rSIFCCON1 = CMD; diff --git a/drivers/video/epaper/auo-tcon-k1900.c b/drivers/video/epaper/auo-tcon-k1900.c index fb14cff..ca52f33 100644 --- a/drivers/video/epaper/auo-tcon-k1900.c +++ b/drivers/video/epaper/auo-tcon-k1900.c @@ -37,14 +37,14 @@ #include -//#define DEBUG_MESSAGES +#define DEBUG_MESSAGES //#define DEBUG_TRACEFUNC -//#define VERBOSE_LEVEL INFO_WARNING +#define VERBOSE_LEVEL INFO_VERBOSE //#define DEBUG_SPI #define MODULE_NAME "AUO-TCON" -#define BUSY_WAIT_TIMEOUT (40*5*2) //panel time out = 1s +#define BUSY_WAIT_TIMEOUT (40*5*2*2) //panel time out = 1s #define SYS_WR_CON (1<<6) #define SYS_OE_CON (1<<7) @@ -56,22 +56,22 @@ enum InfoLevel { - INFO_ERROR = 0, - INFO_WARNING, - INFO_NORMAL, - INFO_VERBOSE, + INFO_ERROR = 0, + INFO_WARNING, + INFO_NORMAL, + INFO_VERBOSE, INFO_DEBUG, }; -# ifndef VERBOSE_LEVEL -# define VERBOSE_LEVEL INFO_WARNING -# endif +# ifndef VERBOSE_LEVEL +# define VERBOSE_LEVEL INFO_WARNING +# endif -# ifdef DEBUG_TRACEFUNC +# ifdef DEBUG_TRACEFUNC static int _dbg_FunctionLevel = 0; -# define MSG(str) {\ +# define MSG(str) {\ int __i;\ printk(KERN_ALERT "+");\ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\ @@ -79,7 +79,7 @@ static int _dbg_FunctionLevel = 0; printk("||" str "\n");\ } -# define DBG(str, ...) {\ +# define DBG(str, ...) {\ int __i;\ printk(KERN_ALERT "+");\ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\ @@ -87,7 +87,7 @@ static int _dbg_FunctionLevel = 0; printk("||" str "\n", __VA_ARGS__);\ } -# define INFOL(level, s) do {\ +# define INFOL(level, s) do {\ if (level <= VERBOSE_LEVEL) {\ int __i;\ printk(KERN_ALERT "+");\ @@ -97,7 +97,7 @@ static int _dbg_FunctionLevel = 0; }\ } while(0) -# define FUNC_IN() {\ +# define FUNC_IN() {\ int __i;\ _dbg_FunctionLevel++;\ printk(KERN_ALERT "+");\ @@ -106,7 +106,7 @@ static int _dbg_FunctionLevel = 0; printk(">> %s() >>\n", __func__);\ } -# define FUNC_OUT() {\ +# define FUNC_OUT() {\ int __i;\ printk(KERN_ALERT "+");\ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\ @@ -115,7 +115,7 @@ static int _dbg_FunctionLevel = 0; _dbg_FunctionLevel--;\ } -# define FUNC_OUTR(val) {\ +# define FUNC_OUTR(val) {\ int __i;\ printk(KERN_ALERT "+");\ for (__i = 0; __i < _dbg_FunctionLevel; __i++)\ @@ -123,40 +123,40 @@ static int _dbg_FunctionLevel = 0; printk("<< %s() = %d <<\n", __func__, val);\ _dbg_FunctionLevel--;\ } -# else /* DEBUG_TRACEFUNC */ +# else /* DEBUG_TRACEFUNC */ -# define MSG(str) do {\ +# define MSG(str) do {\ printk(KERN_ALERT MODULE_NAME ": " str "\n");\ } while(0) -# define DBG(str, ...) do {\ +# define DBG(str, ...) do {\ printk(KERN_ALERT MODULE_NAME ": " str "\n", __VA_ARGS__);\ } while(0) -# define FUNC_IN() do {\ +# define FUNC_IN() do {\ } while(0) -# define FUNC_OUT() do {\ +# define FUNC_OUT() do {\ } while(0) -# define FUNC_OUTR(val) do {\ +# define FUNC_OUTR(val) do {\ printk(KERN_ALERT MODULE_NAME ": %s() return %d\n", __func__, val);\ } while(0) -#define INFOL(level, s) do {\ +# 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 */ +# 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) +# 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 */ // =========================================================================== @@ -171,6 +171,7 @@ static int _dbg_FunctionLevel = 0; static int tcon_inPortraitMode = 0; static int tcon_lastModeWas = 0; + typedef enum Tcon_Speedclasses { EN_I80_NONE = -1, @@ -196,68 +197,81 @@ typedef enum Tcon_PowerMode TCON_POWER_OFF, } Tcon_PowerMode; -static Tcon_SpeedclasseValue tcon_speedtable[] = -{ +static Tcon_SpeedclasseValue tcon_speedtable[] ={ [EN_I80_LANDSCAPE] = { .cs_setup = 0, .wr_setup = 0, - .wr_act = 1, - .wr_hold = 0, + .wr_act = 1, + .wr_hold = 0, }, [EN_I80_PORTRAIT] = { .cs_setup = 0, .wr_setup = 3, - .wr_act = 8, - .wr_hold = 3, + .wr_act = 8, + .wr_hold = 3, }, #if 1 [EN_I80_LANDSCAPE_HANDWRITING] = { .cs_setup = 0, .wr_setup = 1, - .wr_act = 1, - .wr_hold = 0, + .wr_act = 1, + .wr_hold = 0, }, [EN_I80_PORTRAIT_HANDWRITING] = { .cs_setup = 0, .wr_setup = 2, - .wr_act = 6, - .wr_hold = 2, + .wr_act = 6, + .wr_hold = 2, }, #else [EN_I80_PORTRAIT_HANDWRITING] = { .cs_setup = 0, .wr_setup = 1, - .wr_act = 1, - .wr_hold = 0, + .wr_act = 1, + .wr_hold = 0, }, [EN_I80_LANDSCAPE_HANDWRITING] = { .cs_setup = 0, .wr_setup = 2, - .wr_act = 6, - .wr_hold = 2, + .wr_act = 6, + .wr_hold = 2, }, #endif }; +static struct proc_dir_entry *epaperProcEntry; + static Tcon_Speedclasses tcon_currentSpeedClass = EN_I80_NONE; static Tcon_PowerMode tcon_currentPowerMode = TCON_POWER_NORMALMODE; +static unsigned short tcon_currentVersion = 0; + +void tcon_i80bus_set_speed (Tcon_Speedclasses i80_speed, + unsigned short display_w, + unsigned short display_h, + unsigned char set_clock); + +static int tcon_command (sAUOCommand *cmd, char userland); +static int tcon_send_command_start (sAUOCommand *cmd); +static int tcon_send_command_end (sAUOCommand *cmd); + // =========================================================================== // TCON Related functions // =========================================================================== + /* 1. loops = 1 --> 25ns 2. loops = 75 --> 1 us 3. loops = 100000 --> 1ms */ -static inline void tcon_ndelay(unsigned long loops) //in ns +static inline void tcon_ndelay (unsigned long loops) //in ns { - __asm__ volatile ("1:\n" "subs %0, %1, #1\n" "bne 1b":"=r" (loops):"0"(loops)); + __asm__ volatile ("1:\n" "subs %0, %1, #1\n" "bne 1b" : "=r" (loops) : "0"(loops)); } static inline void tcon_delay (unsigned long uTime) @@ -284,12 +298,12 @@ static int tcon_wait_ready (void) iBusyCnt++; if ( iBusyCnt >= BUSY_WAIT_TIMEOUT ) { - return 0; + INFOL(INFO_WARNING, ("TCON Wait timedout!!!")); + return -EIO; } tmp = __raw_readl(S3C2410_GPBDAT); } - - return 1; + return 0; } /* On the i80 port, @@ -300,34 +314,34 @@ static int tcon_wait_ready (void) * nWE -> HWE * OE -> HRD */ -static inline void tcon_i80bus_init_interface(void) +static inline void tcon_i80bus_init_interface (void) { unsigned long tmp; FUNC_IN(); - tmp = __raw_readl(S3C_SYSIFCON0); //polarity of RS, set 1 for normal access - tmp |= (1<<2); + tmp = __raw_readl(S3C_SYSIFCON0); //polarity of RS, set 1 for normal access + tmp |= (1 << 2); __raw_writel(tmp, S3C_SYSIFCON0); - tmp = __raw_readl(S3C_SIFCCON0); // command mode enable - tmp |= (1<<0); + tmp = __raw_readl(S3C_SIFCCON0); // command mode enable + tmp |= (1 << 0); __raw_writel(tmp, S3C_SIFCCON0); FUNC_OUT(); } -static inline void tcon_i80bus_deinit_interface(void) +static inline void tcon_i80bus_deinit_interface (void) { unsigned long tmp; FUNC_IN(); - tmp = __raw_readl(S3C_SIFCCON0); // command mode disable - tmp &= ~(1<<0); + tmp = __raw_readl(S3C_SIFCCON0); // command mode disable + tmp &= ~(1 << 0); __raw_writel(tmp, S3C_SIFCCON0); FUNC_OUT(); } -void tcon_i80bus_set_speed(Tcon_Speedclasses i80_speed, - unsigned short display_w, - unsigned short display_h, - unsigned char set_clock) +void tcon_i80bus_set_speed (Tcon_Speedclasses i80_speed, + unsigned short display_w, + unsigned short display_h, + unsigned char set_clock) { unsigned long tmp; unsigned char clkval = 0; @@ -338,20 +352,18 @@ void tcon_i80bus_set_speed(Tcon_Speedclasses i80_speed, FUNC_IN(); - INFOL(INFO_WARNING, ("speedclass: %d\n", i80_speed)); - - if ( tcon_currentSpeedClass == EN_I80_NONE) + if ( tcon_currentSpeedClass == EN_I80_NONE ) set_clock = true; tcon_currentSpeedClass = i80_speed; - if (set_clock == true) + if ( set_clock == true ) { INFOL(INFO_DEBUG, ("Will set clocks...")); tmp = __raw_readl(S3C_VIDCON0); - tmp = VIDCON0_S_CPU_IF_MAIN | VIDCON0_S_RGB_PAR | \ - VIDCON0_S_VCLK_GATING_OFF | \ + tmp = VIDCON0_S_CPU_IF_MAIN | VIDCON0_S_RGB_PAR | \ + VIDCON0_S_VCLK_GATING_OFF | \ VIDCON0_S_CLKDIR_DIVIDED | VIDCON0_S_CLKSEL_HCLK; __raw_writel(tmp, S3C_VIDCON0); @@ -360,6 +372,7 @@ void tcon_i80bus_set_speed(Tcon_Speedclasses i80_speed, lcd_clock = clk_get(NULL, "hclk"); HCLK = clk_get_rate(lcd_clock); + //printk(KERN_ERR "-------- HCLK: %d --------", HCLK); clkval = (unsigned int)(HCLK / (display_w * display_h * 50 /* FPS ???? */)); vclk = (HCLK / (clkval + 1)) / 1000; @@ -368,21 +381,21 @@ void tcon_i80bus_set_speed(Tcon_Speedclasses i80_speed, tmp |= (clkval << VIDCON0_CLKVAL_F_SHIFT); __raw_writel(tmp, S3C_VIDCON0); } - + tmp = __raw_readl(S3C_SYSIFCON0); tmp = (tcon_speedtable[i80_speed].cs_setup << 16) | - (tcon_speedtable[i80_speed].wr_setup << 12) | - (tcon_speedtable[i80_speed].wr_act << 8) | - (tcon_speedtable[i80_speed].wr_hold << 4) | - (1 << 2) | (1 << 1) | (1); + (tcon_speedtable[i80_speed].wr_setup << 12) | + (tcon_speedtable[i80_speed].wr_act << 8) | + (tcon_speedtable[i80_speed].wr_hold << 4) | + (1 << 2) | (1 << 1) | (1); __raw_writel(tmp, S3C_SYSIFCON0); tmp = __raw_readl(S3C_SYSIFCON1); tmp = (tcon_speedtable[i80_speed].cs_setup << 16) | - (tcon_speedtable[i80_speed].wr_setup << 12) | - (tcon_speedtable[i80_speed].wr_act << 8) | - (tcon_speedtable[i80_speed].wr_hold << 4) | - (1 << 2) | (1 << 1) | (1); + (tcon_speedtable[i80_speed].wr_setup << 12) | + (tcon_speedtable[i80_speed].wr_act << 8) | + (tcon_speedtable[i80_speed].wr_hold << 4) | + (1 << 2) | (1 << 1) | (1); __raw_writel(tmp, S3C_SYSIFCON1); tmp = __raw_readl(S3C_VIDTCON2); @@ -395,17 +408,25 @@ void tcon_i80bus_set_speed(Tcon_Speedclasses i80_speed, static inline void tcon_i80bus_write (int data) { int tmp; - + + if ( (tcon_lastModeWas == 4) && (!tcon_inPortraitMode) ) + tcon_delay(1); + tmp = __raw_readl(S3C_SIFCCON0); // nWE enable tmp |= SYS_WR_CON; __raw_writel(tmp, S3C_SIFCCON0); - if (( !tcon_inPortraitMode ) && (tcon_lastModeWas != 4)) + if ( (!tcon_inPortraitMode) && (tcon_lastModeWas != 4) ) + { tcon_ndelay(25); - else if (( tcon_inPortraitMode ) && (tcon_lastModeWas == 4)) - tcon_ndelay(15); - - + } + else if ( tcon_lastModeWas == 4 ) + { + if ( tcon_inPortraitMode ) + tcon_ndelay(15); + else + tcon_delay(1); + } __raw_writel(data, S3C_SIFCCON1); //rSIFCCON1 = CMD; @@ -414,24 +435,24 @@ static inline void tcon_i80bus_write (int data) __raw_writel(tmp, S3C_SIFCCON0); } -static inline void tcon_i80bus_write_LUT(int data) +static inline void tcon_i80bus_write_LUT (int data) { - int tmp; + int tmp; - tcon_delay(1); - tmp = __raw_readl(S3C_SIFCCON0); // nWE enable - tmp |= SYS_WR_CON; - __raw_writel(tmp, S3C_SIFCCON0); + tcon_delay(1); + tmp = __raw_readl(S3C_SIFCCON0); // nWE enable + tmp |= SYS_WR_CON; + __raw_writel(tmp, S3C_SIFCCON0); - tcon_delay(1); + tcon_delay(1); - __raw_writel(data, S3C_SIFCCON1); //rSIFCCON1 = CMD; + __raw_writel(data, S3C_SIFCCON1); //rSIFCCON1 = CMD; - tcon_delay(1); + tcon_delay(1); - tmp = __raw_readl(S3C_SIFCCON0); // nWE disable - tmp &= ~SYS_WR_CON; - __raw_writel(tmp, S3C_SIFCCON0); + tmp = __raw_readl(S3C_SIFCCON0); // nWE disable + tmp &= ~SYS_WR_CON; + __raw_writel(tmp, S3C_SIFCCON0); } @@ -449,7 +470,7 @@ static inline void tcon_i80bus_read (unsigned short *data) tcon_delay(1); *data = __raw_readl(S3C_SIFCCON2); //CMD = rSIFCCON2; - + tcon_delay(1); tmp = __raw_readl(S3C_SIFCCON0); // nRD disable @@ -457,54 +478,58 @@ static inline void tcon_i80bus_read (unsigned short *data) __raw_writel(tmp, S3C_SIFCCON0); } -static inline void tcon_set_write_to_data(void) +static inline void tcon_set_write_to_data (void) { unsigned long tmp; //FUNC_IN(); - tmp = __raw_readl(S3C_SIFCCON0); + tmp = __raw_readl(S3C_SIFCCON0); // RS high -> D/nC set Data mode - tmp |= (1<<1); + tmp |= (1 << 1); __raw_writel(tmp, S3C_SIFCCON0); tcon_delay(1); //FUNC_OUT(); } -static inline void tcon_set_write_to_command(void) + +static inline void tcon_set_write_to_command (void) { unsigned long tmp; //FUNC_IN(); tmp = __raw_readl(S3C_SIFCCON0); // RS low -> D/nC set Command mode - tmp &= ~(1<<1); + tmp &= ~(1 << 1); __raw_writel(tmp, S3C_SIFCCON0); tcon_delay(1); //FUNC_OUT(); } -static inline void tcon_enable_write(void) + +static inline void tcon_enable_write (void) { unsigned long tmp; FUNC_IN(); tmp = __raw_readl(S3C_SIFCCON0); // nWE -> HWE enable - tmp |= (1<<6); + tmp |= (1 << 6); __raw_writel(tmp, S3C_SIFCCON0); tcon_delay(1); FUNC_OUT(); } -static inline void tcon_disable_write(void) + +static inline void tcon_disable_write (void) { unsigned long tmp; FUNC_IN(); tmp = __raw_readl(S3C_SIFCCON0); // nWE -> HWE disable - tmp &= ~(1<<6); + tmp &= ~(1 << 6); __raw_writel(tmp, S3C_SIFCCON0); tcon_delay(1); FUNC_OUT(); } -static inline void tcon_enable_read(void) + +static inline void tcon_enable_read (void) { unsigned long tmp; FUNC_IN(); @@ -514,7 +539,8 @@ static inline void tcon_enable_read(void) tcon_delay(1); FUNC_OUT(); } -static inline void tcon_disable_read(void) + +static inline void tcon_disable_read (void) { unsigned long tmp; FUNC_IN(); @@ -524,101 +550,251 @@ static inline void tcon_disable_read(void) tcon_delay(1); FUNC_OUT(); } -static inline void tcon_select_chip(void) + +static inline void tcon_select_chip (void) { unsigned long tmp; FUNC_IN(); tmp = __raw_readl(S3C_SIFCCON0); // Chip Select - tmp |= (1<<8); + tmp |= (1 << 8); __raw_writel(tmp, S3C_SIFCCON0); tcon_delay(1); FUNC_OUT(); } -static inline void tcon_unselect_chip(void) + +static inline void tcon_unselect_chip (void) { unsigned long tmp; FUNC_IN(); tmp = __raw_readl(S3C_SIFCCON0); // nCS0(Main) enable - tmp &= ~(1<<8); + tmp &= ~(1 << 8); __raw_writel(tmp, S3C_SIFCCON0); tcon_delay(1); FUNC_OUT(); } -static inline void tcon_set_power_on(void) +static inline void tcon_goto_sleep (void) +{ + /* Set GPIO accordingly */ + unsigned long tmp = __raw_readl(S3C2410_GPBDAT); + tmp &= ~(1 << 1); //Set SLP_N to low + __raw_writel(tmp, S3C2410_GPBDAT); + msleep(10); +} + +static inline void tcon_wakeup_sleep (void) { unsigned long tmp = __raw_readl(S3C2410_GPBDAT); - tmp |= (1 << 3); + tmp |= (1 << 1); //Set SLP_N to high __raw_writel(tmp, S3C2410_GPBDAT); + msleep(10); +} + +static inline void tcon_reset (void) +{ + // LCD module reset + unsigned long tmp = __raw_readl(S3C2410_GPDDAT); + tmp |= (1 << 9); + __raw_writel(tmp, S3C2410_GPDDAT); + + tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to LOW + tmp &= ~(1 << 9); + __raw_writel(tmp, S3C2410_GPDDAT); + + tcon_delay(5); + + tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to HIGH + tmp |= (1 << 9); + __raw_writel(tmp, S3C2410_GPDDAT); + + // delay about 10ms + msleep(10); + + tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false); + + /* Reseting the TCON will set the tcon in Level0 power mode */ + tcon_currentPowerMode = TCON_POWER_NORMALMODE; +} + +static inline void tcon_set_power_on (void) +{ + unsigned long tmp; + tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 800, 600, true); + + // POWER pin config + tmp = __raw_readl(S3C2410_GPBCON); + tmp = (tmp & ~(3 << 6)) | (1 << 6); + __raw_writel(tmp, S3C2410_GPBCON); + + // BUSY pin config + tmp = __raw_readl(S3C2410_GPBCON); + tmp = (tmp & ~(3 << 4)); + __raw_writel(tmp, S3C2410_GPBCON); + + // SLEEP pin config + tmp = __raw_readl(S3C2410_GPBCON); + tmp = (tmp & ~(3 << 2)) | (1 << 2); + __raw_writel(tmp, S3C2410_GPBCON); + + msleep(1); + + // Panel power on + tmp = __raw_readl(S3C2410_GPBDAT); + tmp |= (1 << 3); + //SLP_N high + tmp |= (1 << 1); + __raw_writel(tmp, S3C2410_GPBDAT); + + msleep(100); + + tcon_reset(); tcon_currentPowerMode = TCON_POWER_NORMALMODE; } -static inline void tcon_set_power_off(void) +static inline int tcon_set_power_off (void) { - unsigned long tmp = __raw_readl(S3C2410_GPBDAT); - tmp &= ~(1 << 3); - __raw_writel(tmp, S3C2410_GPBDAT); - + unsigned long tmp; + sAUOCommand cmd; + + switch ( tcon_currentPowerMode ) + { + default: + return -EBADF; /* Invalide power mode, can't shutdown... */ + break; + + case TCON_POWER_NORMALMODE: + cmd.cmd = AUOCMD_STANDBY; + tcon_command(&cmd, false); + + case TCON_POWER_STANDBYMODE: + tcon_goto_sleep(); + + case TCON_POWER_SLEEPMODE: + /*Standby -> Off = shutdown the power pin */ + tmp = __raw_readl(S3C2410_GPBDAT); + tmp &= ~(1 << 3); + __raw_writel(tmp, S3C2410_GPBDAT); + + case TCON_POWER_OFF: + break; + } + tcon_currentPowerMode = TCON_POWER_OFF; + return 0; } +struct tcon_info +{ + unsigned short temperature, + epd_type, + panel_size_int, + panel_size_float, + model, + lut_version, + tcon_version; +}; -int tcon_send_command_start(sAUOCommand *cmd) +static void tcon_get_info (struct tcon_info *info) +{ + sAUOCommand cmd; + unsigned short buf[4] = { 0, 0, 0, 0 }; + + if ( info == NULL ) + return; + + cmd.cmd = AUOCMD_READ_FUNC; + cmd.data = buf; + cmd.datalen = 8; + + tcon_command(&cmd, false); + + info->temperature = buf[0] & 0x01FF; + info->epd_type = buf[1] & 0x00FF; + info->panel_size_int = (buf[2] & 0xFC00) >> 10; + info->panel_size_float = (buf[2] & 0x03C0) >> 6; + info->model = buf[2] & 0x003F; + info->lut_version = buf[3] & 0x00FF; + info->tcon_version = (buf[3] & 0xFF00) >> 8; + + tcon_currentVersion = info->tcon_version; +} + +static void tcon_display_info (void) +{ + struct tcon_info info; + tcon_get_info(&info); + printk("TCON FW v%d, LUT v%d, EPD {v[%d];Size[%d:%d];Model[%d]}\n", + info.tcon_version, info.lut_version, + info.epd_type, info.panel_size_int, info.panel_size_float, info.model); + if ( tcon_currentVersion != AUO_FIRMWARE_VERSION ) + printk(KERN_WARNING "!!! Warning: TCON Firmware version and Driver version mismatch !!!\n"); +} + +static int tcon_send_command_start (sAUOCommand *cmd) { FUNC_IN(); - INFOL(INFO_DEBUG,("cmd #%08lX", cmd->cmd)); + INFOL(INFO_DEBUG, ("cmd #%08lX", cmd->cmd)); /* First: verify that the K1900 is ready */ INFOL(INFO_DEBUG, ("/* First: verify that the K1900 is ready */")); - if (GET_COMMAND_NEED_WAIT(cmd->cmd) != 0x00) + if ( GET_COMMAND_NEED_WAIT(cmd->cmd) != 0x00 ) { INFOL(INFO_DEBUG, ("Wait for non BUSY...")); - tcon_wait_ready(); + // TODO: return error on timeout + if ( tcon_wait_ready() < 0 ) + { + INFOL(INFO_ERROR, ("Waiting timed out")); + return -EIO; + } } - if (cmd->cmd == AUOCMD_STANDBY) + if ( AUOCMD_EQUAL(cmd->cmd, AUOCMD_STANDBY) ) + { + INFOL(INFO_VERBOSE, ("TCON Switching to Standby mode (Level1)")); tcon_currentPowerMode = TCON_POWER_STANDBYMODE; - else if (cmd->cmd == AUOCMD_WAKEUP) + } + else if ( AUOCMD_EQUAL(cmd->cmd, AUOCMD_WAKEUP) ) + { + INFOL(INFO_VERBOSE, ("TCON Switching to Normal mode (Level0)")); tcon_currentPowerMode = TCON_POWER_NORMALMODE; - else if (cmd->cmd == AUOCMD_INIT_SET) + } + else if ( AUOCMD_EQUAL(cmd->cmd, AUOCMD_INIT_SET) ) { - tcon_inPortraitMode = ~(cmd->params[0]) & (0x1 << 10); - if (tcon_lastModeWas != 4) - { - if (tcon_inPortraitMode) - tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false); - else - tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, false); - } - else - { - if (tcon_inPortraitMode) - tcon_i80bus_set_speed(EN_I80_PORTRAIT_HANDWRITING, 800, 600, false); + tcon_inPortraitMode = ~(cmd->params[0]) & (0x1 << 10); + if ( tcon_lastModeWas != 4 ) + { + if ( tcon_inPortraitMode ) + tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false); else - tcon_i80bus_set_speed(EN_I80_LANDSCAPE_HANDWRITING, 600, 800, false); - } - INFOL(INFO_DEBUG, ("Rotation set to 0x%08X...", tcon_inPortraitMode)); - } - else if (cmd->cmd == AUOCMD_DISPLAY_START) - { - INFOL(INFO_VERBOSE, ("Display Start (lastMode: %d)...", tcon_lastModeWas)); - if (((cmd->params[0] >> 12) & 0x07) == 4) /* Handwriting mode... */ - { - INFOL(INFO_VERBOSE, ("Mode 4")); - if (tcon_inPortraitMode) - tcon_i80bus_set_speed(EN_I80_PORTRAIT_HANDWRITING, 800, 600, false); + tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, false); + } + else + { + if ( tcon_inPortraitMode ) + tcon_i80bus_set_speed(EN_I80_PORTRAIT_HANDWRITING, 800, 600, false); else tcon_i80bus_set_speed(EN_I80_LANDSCAPE_HANDWRITING, 600, 800, false); } - else if (tcon_lastModeWas == 4) + INFOL(INFO_DEBUG, ("Rotation set to 0x%08X...", tcon_inPortraitMode)); + } + else if ( AUOCMD_EQUAL(cmd->cmd, AUOCMD_DISPLAY_START) ) + { + INFOL(INFO_DEBUG, ("Display Start (lastMode: %d)...", tcon_lastModeWas)); + if ( ((cmd->params[0] >> 12) & 0x07) == 4 ) /* Handwriting mode... */ { - INFOL(INFO_VERBOSE, ("--- NOT --- mode 4 (%d)", ((cmd->params[0] >> 12) & 0x07))); - if (tcon_inPortraitMode) - tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false); + if ( tcon_inPortraitMode ) + tcon_i80bus_set_speed(EN_I80_PORTRAIT_HANDWRITING, 800, 600, false); + else + tcon_i80bus_set_speed(EN_I80_LANDSCAPE_HANDWRITING, 600, 800, false); + } + else if ( tcon_lastModeWas == 4 ) + { + if ( tcon_inPortraitMode ) + tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false); else tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, false); - } + } tcon_lastModeWas = ((cmd->params[0] >> 12) & 0x07); } /* Second: init the i80 interface */ @@ -636,7 +812,7 @@ int tcon_send_command_start(sAUOCommand *cmd) /* Sixth: If parameters is needed, send them */ INFOL(INFO_DEBUG, ("/* Sixth: If parameters is needed, send them */")); - if (GET_COMMAND_PARAM_NUM(cmd->cmd) > 0) + if ( GET_COMMAND_PARAM_NUM(cmd->cmd) > 0 ) { int i, paramNumbers = GET_COMMAND_PARAM_NUM(cmd->cmd); @@ -644,10 +820,10 @@ int tcon_send_command_start(sAUOCommand *cmd) tcon_set_write_to_data(); - for (i = 0; i < paramNumbers; i++) + for ( i = 0; i < paramNumbers; i++ ) { - INFOL(INFO_DEBUG, (" parameter [%02d] = 0x%04X", i, cmd->params[i])); - tcon_i80bus_write(cmd->params[i]); + INFOL(INFO_DEBUG, (" parameter [%02d] = 0x%04X", i, cmd->params[i])); + tcon_i80bus_write(cmd->params[i]); } } @@ -655,7 +831,7 @@ int tcon_send_command_start(sAUOCommand *cmd) return 0; } -int tcon_send_data(unsigned short *buffer, unsigned long bufferLen) +static int tcon_send_data (unsigned short *buffer, unsigned long bufferLen) { /* Seventh: Send data if needed */ unsigned long i; @@ -665,7 +841,7 @@ int tcon_send_data(unsigned short *buffer, unsigned long bufferLen) tcon_set_write_to_data(); - for (i = 0; i < bufferLen; i++) + for ( i = 0; i < bufferLen; i++ ) { tcon_i80bus_write(buffer[i]); } @@ -673,7 +849,7 @@ int tcon_send_data(unsigned short *buffer, unsigned long bufferLen) return 0; } -int tcon_send_lut_data(unsigned short *buffer, unsigned long bufferLen) +static int tcon_send_lut_data (unsigned short *buffer, unsigned long bufferLen) { /* Seventh: Send data if needed */ unsigned long i; @@ -683,7 +859,7 @@ int tcon_send_lut_data(unsigned short *buffer, unsigned long bufferLen) tcon_set_write_to_data(); - for (i = 0; i < bufferLen; i++) + for ( i = 0; i < bufferLen; i++ ) { tcon_delay(1); tcon_wait_ready(); @@ -695,38 +871,37 @@ int tcon_send_lut_data(unsigned short *buffer, unsigned long bufferLen) return 0; } - -int tcon_read_data(unsigned short *buffer, unsigned long bufferLen) +static int tcon_read_data (unsigned short *buffer, unsigned long bufferLen) { unsigned long i; - //FUNC_IN(); + FUNC_IN(); //INFOL(INFO_VERBOSE, ("Bufferlen: %ld", bufferLen)); tcon_set_write_to_data(); - for (i = 0; i < bufferLen; i++) + for ( i = 0; i < bufferLen; i++ ) { tcon_i80bus_read(&(buffer[i])); } - //FUNC_OUT(); + FUNC_OUT(); return 0; } -int tcon_send_command_end(sAUOCommand *cmd) +static int tcon_send_command_end (sAUOCommand *cmd) { FUNC_IN(); - INFOL(INFO_DEBUG,("cmd #%08lX START:[#%08X]", cmd->cmd, AUOCMD_DISPLAY_START)); - if (cmd->cmd == AUOCMD_DISPLAY_START) - { - tcon_set_write_to_command(); - INFOL(INFO_DEBUG, ("/* Eight: Send STOP command */")); - tcon_i80bus_write(AUOCMD_DISPLAY_STOP & 0xFFFF); - tcon_set_write_to_data(); - } + INFOL(INFO_DEBUG, ("cmd #%08lX START:[#%08X]", cmd->cmd, AUOCMD_DISPLAY_START)); + if ( AUOCMD_EQUAL(cmd->cmd, AUOCMD_DISPLAY_START) ) + { + tcon_set_write_to_command(); + INFOL(INFO_DEBUG, ("/* Eight: Send STOP command */")); + tcon_i80bus_write(AUOCMD_DISPLAY_STOP & 0xFFFF); + tcon_set_write_to_data(); + } - INFOL(INFO_DEBUG, ("/* Nineth: Close all */")); + INFOL(INFO_DEBUG, ("/* Nineth: Close all */")); tcon_unselect_chip(); tcon_i80bus_deinit_interface(); @@ -742,17 +917,18 @@ int tcon_send_command_end(sAUOCommand *cmd) #define TCON_SPI_DO S3C2410_GPE12 #define TCON_SPI_CS S3C2410_GPL13 -static void tcon_spi_init(void) +static int tcon_spi_init (void) { FUNC_IN(); /* First be sure that the Wifi is off */ /* GPK5 = PA 3.3V */ - writel((readl(S3C2416_GPKDAT) & ~(1<<5)), S3C2416_GPKDAT); + writel((readl(S3C2416_GPKDAT) & ~(1 << 5)), S3C2416_GPKDAT); /* GPK6 = PA 1.8V */ - writel((readl(S3C2416_GPKDAT) & ~(1<<6)), S3C2416_GPKDAT); + writel((readl(S3C2416_GPKDAT) & ~(1 << 6)), S3C2416_GPKDAT); /* Next, shutdown the TCON */ - tcon_set_power_off(); + if ( tcon_set_power_off() != 0 ) + return -1; mdelay(2000); //GPD8, RESET @@ -780,19 +956,20 @@ static void tcon_spi_init(void) /* GPE13 = SPI CLK */ s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_OUTP); s3c2410_gpio_setpin(S3C2410_GPE13, 0); - + mdelay(50); /* We are ready ! */ FUNC_OUT(); + return 0; } -static void tcon_spi_deinit(void) +static void tcon_spi_deinit (void) { FUNC_IN(); /* First, switch the SPI */ s3c2410_gpio_setpin(S3C2410_GPH6, 1); - + /* Then, restore GPIOs */ s3c2410_gpio_cfgpin(S3C2410_GPL13, S3C2410_GPL13_SS0); /* GPE11 = SPI DI */ @@ -801,7 +978,7 @@ static void tcon_spi_deinit(void) s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0); /* GPE13 = SPI CLK */ s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0); - + /* Next, switch back on the TCON */ tcon_set_power_on(); s3c2410_gpio_setpin(S3C2410_GPD8, 1); @@ -813,9 +990,9 @@ static void tcon_spi_deinit(void) static inline unsigned char tcon_spi_read (void) { unsigned char k, - tmp_data = 0, - i = 0; - u32 read_pin; + tmp_data = 0, + i = 0; + u32 read_pin; #ifdef DEBUG_SPI char strobe_str[9]; strobe_str[8] = 0; @@ -828,7 +1005,7 @@ static inline unsigned char tcon_spi_read (void) udelay(2); /* Sample */ - read_pin = s3c2410_gpio_getpin(TCON_SPI_DI);//(readl(S3C2410_GPEDAT) & (1 << 11)); + read_pin = s3c2410_gpio_getpin(TCON_SPI_DI); //(readl(S3C2410_GPEDAT) & (1 << 11)); if ( read_pin ) { @@ -837,7 +1014,7 @@ static inline unsigned char tcon_spi_read (void) } #ifdef DEBUG_SPI - strobe_str[k] = (read_pin?'-':'_'); + strobe_str[k] = (read_pin ? '-' : '_'); #endif /* ACK bit read */ @@ -852,7 +1029,7 @@ static inline unsigned char tcon_spi_read (void) return (tmp_data); } -static inline void tcon_spi_write(unsigned char value) +static inline void tcon_spi_write (unsigned char value) { unsigned char k; #ifdef DEBUG_SPI @@ -869,7 +1046,7 @@ static inline void tcon_spi_write(unsigned char value) s3c2410_gpio_setpin(TCON_SPI_DO, 0); #ifdef DEBUG_SPI - strobe_str[k] = ((value&0x80)?'-':'_'); + strobe_str[k] = ((value & 0x80) ? '-' : '_'); #endif /* Strobe clock */ @@ -886,7 +1063,7 @@ static inline void tcon_spi_write(unsigned char value) #endif } -static unsigned char tcon_spi_flash_read(unsigned char value) +static unsigned char tcon_spi_flash_read (unsigned char value) { unsigned char ret; s3c2410_gpio_setpin(TCON_SPI_CS, 0); @@ -901,18 +1078,18 @@ static unsigned char tcon_spi_flash_read(unsigned char value) return ret; } -static void tcon_spi_flash_write(unsigned char value) +static void tcon_spi_flash_write (unsigned char value) { s3c2410_gpio_setpin(TCON_SPI_CS, 0); udelay(50); tcon_spi_write(value); - + s3c2410_gpio_setpin(TCON_SPI_CS, 1); udelay(50); } -static void tcon_spi_flash_waitready(void) +static void tcon_spi_flash_waitready (void) { unsigned char r_data; FUNC_IN(); @@ -926,33 +1103,33 @@ static void tcon_spi_flash_waitready(void) udelay(50); s3c2410_gpio_setpin(TCON_SPI_CS, 1); INFOL(INFO_DEBUG, ("r_data: 0x%02x [SRWD:%c BP2:%d BP1:%d BP0:%d, WEL:%c, WIP:%c]\n", r_data, - (r_data & 0x80)?'E':'D', - (r_data & 0x10)?1:0, - (r_data & 0x08)?1:0, - (r_data & 0x04)?1:0, - (r_data & 0x02)?'E':'D', - (r_data & 0x01)?'W':'r')); + (r_data & 0x80) ? 'E' : 'D', + (r_data & 0x10) ? 1 : 0, + (r_data & 0x08) ? 1 : 0, + (r_data & 0x04) ? 1 : 0, + (r_data & 0x02) ? 'E' : 'D', + (r_data & 0x01) ? 'W' : 'r')); msleep(20); } while ( r_data & 0x01 ); FUNC_OUT(); } -static void tcon_spi_flash_writepage(unsigned long addr, unsigned char *buffer, unsigned short buffer_len) +static void tcon_spi_flash_writepage (unsigned long addr, unsigned char *buffer, unsigned short buffer_len) { int i; FUNC_IN(); s3c2410_gpio_setpin(TCON_SPI_CS, 0); udelay(50); - tcon_spi_write(0x02); //Write Page Program command - tcon_spi_write( (addr & 0xFF0000) >> 16 ); - tcon_spi_write( (addr & 0xFF00) >> 8 ); - tcon_spi_write( (addr & 0xFF) ); + tcon_spi_write(0x02); //Write Page Program command + tcon_spi_write((addr & 0xFF0000) >> 16); + tcon_spi_write((addr & 0xFF00) >> 8); + tcon_spi_write((addr & 0xFF)); - for(i=0; icmd) != 0 ) + { + user_buflen = cmd->datalen; + user_buffer = (unsigned char *)cmd->data; + + while ( user_buflen != 0 ) + { + copysize = user_buflen; + + if ( user_buflen > sizeof (buffer) ) + copysize = sizeof (buffer); + if ( GET_COMMAND_READ_WRITE(cmd->cmd) == 0 ) + { /* Write mode */ + if (userland) + { + if ( copy_from_user(buffer, user_buffer, copysize) ) + { + ret = -EFAULT; + goto exit; + } + } + else + { + memcpy(buffer, user_buffer, copysize); + } + } + + copysize16 = (copysize + 1) / 2; + + ptr16 = (unsigned short *)buffer; + if ( GET_COMMAND_READ_WRITE(cmd->cmd) == 0 ) + { /* Write mode */ + if ( cmd->cmd == AUOCMD_LUT_START ) + tcon_send_lut_data((unsigned short *)buffer, copysize16); + else + tcon_send_data((unsigned short *)buffer, copysize16); + } + else + { /* Read mode */ + tcon_read_data((unsigned short *)buffer, copysize16); + if (userland) + { + if ( copy_to_user(user_buffer, buffer, copysize) ) + return -EFAULT; + } + else + { + memcpy(user_buffer, buffer, copysize); + } + } + + user_buflen -= copysize; + user_buffer += copysize; + } + } + tcon_send_command_end(cmd); + +exit: + return ret; +} + +static int tcon_ioctl (struct inode *inode, struct file *file, + unsigned int ioctl_cmd, unsigned long arg) +{ + sAUOCommand cmd; + unsigned char buffer[2048]; + unsigned char *user_buffer; + unsigned long user_buflen, copysize; void __user *argp = (void __user *)arg; - int block_id = 0; + int block_id; int flash_addr; int ret = -EINVAL; FUNC_IN(); - INFOL(INFO_VERBOSE, ("Receive IOTCL #08%X", ioctl_cmd)); + + block_id = 0; + + //INFOL(INFO_VERBOSE, ("Receive IOTCL #08%X", ioctl_cmd)); switch ( ioctl_cmd ) { case IOCTL_AUO_SENDCOMMAND: @@ -1016,119 +1272,76 @@ int tcon_ioctl (struct inode *inode, struct file *file, return -EFAULT; /* Prevent to send command if the user don't provide a buffer */ - if ((GET_COMMAND_READ_WRITE(cmd.cmd) != 0) && (cmd.datalen == 0)) + if ( (GET_COMMAND_READ_WRITE(cmd.cmd) != 0) && (cmd.datalen == 0) ) return -EFAULT; /* Prevent if we set data and data prt is NULL */ - if (( GET_COMMAND_HAVE_DATA(cmd.cmd) != 0 ) && (cmd.datalen > 0) && (cmd.data == NULL)) + if ( (GET_COMMAND_HAVE_DATA(cmd.cmd) != 0) && (cmd.datalen > 0) && (cmd.data == NULL) ) return -EFAULT; - - /* Now execute the command */ - tcon_send_command_start(&cmd); - ///INFOL(INFO_VERBOSE, ("/* Seventh: Send data if needed */")); - if ( GET_COMMAND_HAVE_DATA(cmd.cmd) != 0 ) - { - //INFOL(INFO_VERBOSE, ("Yes, we have data to send!")); - user_buflen = cmd.datalen; - user_buffer = (unsigned char *)cmd.data; + ret = tcon_command(&cmd, true); - while ( user_buflen != 0 ) - { - copysize = user_buflen; + //INFOL(INFO_VERBOSE, ("tcon_command returned: %d", ret)); - if ( user_buflen > sizeof (buffer) ) - copysize = sizeof (buffer); - if (GET_COMMAND_READ_WRITE(cmd.cmd) == 0) - { /* Write mode */ - if ( copy_from_user(buffer, user_buffer, copysize) ) - return -EFAULT; - } - - copysize16 = (copysize + 1) / 2; - //printk(KERN_ERR "cp16=%ld cp=%ld\n", copysize16, copysize); - - ptr16 = (unsigned short *)buffer; - if (GET_COMMAND_READ_WRITE(cmd.cmd) == 0) - { /* Write mode */ - INFOL(INFO_DEBUG, ("Will send block %d", block_id++)); - if (cmd.cmd == AUOCMD_LUT_START) - tcon_send_lut_data((unsigned short *)buffer, copysize16); - else - tcon_send_data((unsigned short *)buffer, copysize16); - } - else - { - tcon_read_data((unsigned short *)buffer, copysize16); - if ( copy_to_user(user_buffer, buffer, copysize) ) - return -EFAULT; - } - - user_buflen -= copysize; - user_buffer += copysize; - } - } - - - tcon_send_command_end(&cmd); - ret = 0; break; case IOCTL_AUO_RESET: - tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to LOW - tmp &= ~(1 << 9); - __raw_writel(tmp, S3C2410_GPDDAT); - - tcon_delay(5); - - tmp = __raw_readl(S3C2410_GPDDAT); // RST_N goes to HIGH - tmp |= (1 << 9); - __raw_writel(tmp, S3C2410_GPDDAT); - - // delay about 10ms - msleep(10); - - tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false); - + tcon_reset(); ret = 0; break; + case IOCTL_AUO_POWEROFF: + // + INFOL(INFO_VERBOSE, ("Switching to power OFF (Level3)...")); + ret = tcon_set_power_off(); + break; + + case IOCTL_AUO_POWERON: + // + INFOL(INFO_VERBOSE, ("Switching to power Normal Mode (Level0)...")); + tcon_set_power_on(); + ret = 0; + break; + + case IOCTL_AUO_WAITBUSY: + ret = tcon_wait_ready(); + break; + case IOCTL_AUO_SLEEP: /* Only accept go to sleep if we are in standby, or else it will fail */ - if (tcon_currentPowerMode == TCON_POWER_STANDBYMODE) + if ( tcon_currentPowerMode == TCON_POWER_STANDBYMODE ) { + INFOL(INFO_VERBOSE, ("Switching Standby to Sleep mode (Level2)...")); tcon_currentPowerMode = TCON_POWER_SLEEPMODE; - /* Set GPIO accordingly */ - tmp = __raw_readl(S3C2410_GPBDAT); - tmp &= ~(1 << 1); //Set SLP_N to low - __raw_writel(tmp, S3C2410_GPBDAT); - msleep(10); + tcon_goto_sleep(); ret = 0; } else + { ret = -ENAVAIL; + } break; case IOCTL_AUO_WAKEUP: /* Only accept go to sleep if we are in standby, or else it will fail */ - if (tcon_currentPowerMode == TCON_POWER_SLEEPMODE) + if ( tcon_currentPowerMode == TCON_POWER_SLEEPMODE ) { + INFOL(INFO_VERBOSE, ("Switching Sleep to Standby Mode (Level1)...")); tcon_currentPowerMode = TCON_POWER_STANDBYMODE; /* Set GPIO accordingly */ - tmp = __raw_readl(S3C2410_GPBDAT); - tmp |= (1 << 1); //Set SLP_N to high - __raw_writel(tmp, S3C2410_GPBDAT); - msleep(10); + + tcon_wakeup_sleep(); + ret = 0; } else ret = -ENAVAIL; break; - + case IOCTL_AUO_UPDATEFW: INFOL(INFO_VERBOSE, ("Starting update of TCON firmware...")); if ( copy_from_user(&cmd, argp, sizeof (cmd)) ) @@ -1137,25 +1350,23 @@ int tcon_ioctl (struct inode *inode, struct file *file, return -EFAULT; } - INFOL(INFO_VERBOSE, ("Starting update of TCON firmware...")); - - if ((cmd.data == NULL) || (cmd.datalen == 0)) + if ( (cmd.data == NULL) || (cmd.datalen == 0) ) { INFOL(INFO_ERROR, ("Parameters error...")); return -EFAULT; } /* First init SPI */ - INFOL(INFO_VERBOSE, ("Will init BitBang SPI...")); + INFOL(INFO_DEBUG, ("Will init BitBang SPI...")); tcon_spi_init(); mdelay(3000); - + flash_addr = 0; INFOL(INFO_VERBOSE, ("Erasing SPI flash...")); /* Erase Flash */ - tcon_spi_flash_write(0x06); //Setting Write Enable Latch bit - tcon_spi_flash_write(0x60); //Write Chip Erase command + tcon_spi_flash_write(0x06); //Setting Write Enable Latch bit + tcon_spi_flash_write(0x60); //Write Chip Erase command msleep(100); tcon_spi_flash_waitready(); @@ -1175,7 +1386,7 @@ int tcon_ioctl (struct inode *inode, struct file *file, copysize = 256; if ( copy_from_user(buffer, user_buffer, copysize) ) - return -EFAULT; + return -EFAULT; /* Send Buffer data */ tcon_spi_flash_write(0x06); /* Enable write... */ @@ -1190,9 +1401,34 @@ int tcon_ioctl (struct inode *inode, struct file *file, tcon_spi_deinit(); break; + case IOCTL_AUO_PROGRESSBAR: + { + unsigned short *buf; + copysize = (arg * 492) / 100; + copysize -= (copysize % 8); + buf = (unsigned short *)kmalloc(copysize * 24 * 4, GFP_KERNEL); + if ( buf ) + { + memset(buf, 0x00, copysize * 24 * 4); + + cmd.cmd = AUOCMD_DISPLAY_START; + cmd.params[0] = AUO_DSPPARAM_MODE_GRAYnFLASH | ((((600 - 500) / 2) + 4) & 0x0FFF); + cmd.params[1] = (((800 - (30 + 20)) + 4) & 0x0FFF); + cmd.params[2] = ((copysize) & 0x0FFF); + cmd.params[3] = (24 & 0x0FFF); + cmd.data = buf; + cmd.datalen = ((copysize>>1) * 24) >> 1; + tcon_command(&cmd, false); + + kfree(buf); + } + + ret = 0; + } + break; default: - printk(KERN_WARNING "Invalid ioctl"); + printk(KERN_WARNING "Invalid IOCTL"); ret = -EINVAL; break; } @@ -1201,8 +1437,7 @@ int tcon_ioctl (struct inode *inode, struct file *file, return ret; } // =========================================================================== -static struct file_operations s_tcon_fops = -{ +static struct file_operations s_tcon_fops ={ owner : THIS_MODULE, read : tcon_read, ioctl : tcon_ioctl, @@ -1210,8 +1445,7 @@ static struct file_operations s_tcon_fops = release : tcon_release, }; -static struct miscdevice s_tcon_dev = -{ +static struct miscdevice s_tcon_dev ={ .minor = 242, .name = "epaper", .fops = &s_tcon_fops, @@ -1230,13 +1464,14 @@ static int tcon_probe (struct platform_device *dev) printk(" ok\n"); ret = 0; + printk("Cybook Orizon Layout\n"); + // set gpio for lcd tmp = __raw_readl(S3C2410_GPCCON); //tmp = (tmp & ~(0xffff03ff))|(0xaaaa02aa); tmp = (tmp & ~(0xffff033f)) | (0xaaaa022a); //Do not config SYS_CS1(GPC3) __raw_writel(tmp, S3C2410_GPCCON); - printk("Cybook Orizon Layout\n"); tmp = __raw_readl(S3C2410_GPDCON); //tmp=0x40000 tmp = (tmp & ~(0x0CFFFF)) | (0x04AAAA); __raw_writel(tmp, S3C2410_GPDCON); // GPD9 is RST_N @@ -1244,6 +1479,7 @@ static int tcon_probe (struct platform_device *dev) __raw_writel(0, S3C2410_GPCUP); //S3C2410_GPCUP = 0; __raw_writel(0, S3C2410_GPDUP); //S3C2410_GPDUP = 0; +#if 0 tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 800, 600, true); // POWER pin config @@ -1272,6 +1508,7 @@ static int tcon_probe (struct platform_device *dev) msleep(100); + // LCD module reset tmp = __raw_readl(S3C2410_GPDDAT); tmp |= (1 << 9); @@ -1289,8 +1526,13 @@ static int tcon_probe (struct platform_device *dev) // delay about 10ms msleep(10); - + tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, false); +#else + tcon_set_power_on(); +#endif + + tcon_display_info(); } else printk(" not ok\n"); @@ -1313,7 +1555,9 @@ static int tcon_resume (struct platform_device *dev) { FUNC_IN(); - if (tcon_inPortraitMode) + //tcon_set_power_on(); + + if ( tcon_inPortraitMode ) tcon_i80bus_set_speed(EN_I80_PORTRAIT, 800, 600, true); else tcon_i80bus_set_speed(EN_I80_LANDSCAPE, 600, 800, true); @@ -1329,11 +1573,13 @@ static int tcon_suspend (struct platform_device *dev, pm_message_t state) DBG("state event: %X", state.event); + //tcon_set_power_off(); + FUNC_OUT(); return 0; } // --------------------------------------------------------------------------- -static struct platform_driver tcon_driver ={ +static struct platform_driver tcon_driver = { .driver = { .name = "epaper-tcon", @@ -1347,6 +1593,24 @@ static struct platform_driver tcon_driver ={ // --------------------------------------------------------------------------- // =========================================================================== +static int tcon_procReadEpaper (char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + + struct tcon_info info; + tcon_get_info(&info); + + len = sprintf(page, "tcon_k1900;%d;%d;%d;%d;%d;%d;%d;%d;%d\n", + tcon_currentPowerMode, tcon_currentSpeedClass, + info.tcon_version, info.lut_version, + info.temperature>>1, info.model, + info.epd_type, info.panel_size_int, info.panel_size_float); + + return len; +} +// =========================================================================== + static int __init tcon_init (void) { int ret = 0; @@ -1362,6 +1626,10 @@ static int __init tcon_init (void) platform_driver_register(&tcon_driver); + epaperProcEntry = create_proc_entry("epaper", 0644, proc_root_driver); + epaperProcEntry->read_proc = tcon_procReadEpaper; + epaperProcEntry->owner = THIS_MODULE; + exit: FUNC_OUTR(ret); return ret; @@ -1375,6 +1643,7 @@ static void __exit tcon_exit (void) platform_driver_unregister(&tcon_driver); misc_deregister(&s_tcon_dev); + remove_proc_entry("epaper", proc_root_driver); FUNC_OUT(); } // --------------------------------------------------------------------------- diff --git a/include/linux/auofb_ioctl.h b/include/linux/auofb_ioctl.h index f924ecc..6a4f32f 100644 --- a/include/linux/auofb_ioctl.h +++ b/include/linux/auofb_ioctl.h @@ -21,7 +21,7 @@ #ifndef AUOFB_IOCTL_H #define AUOFB_IOCTL_H -#define AUO_FIRMWARE_VERSION 33 +#define AUO_FIRMWARE_VERSION 39 #pragma pack(1) typedef struct sAUOCommand_t @@ -45,6 +45,8 @@ typedef struct sAUOCommand_t #define IOCTL_AUO_POWERON (IOCTL_AUO_PREFIX | 0x05) #define IOCTL_AUO_POWEROFF (IOCTL_AUO_PREFIX | 0x06) #define IOCTL_AUO_UPDATEFW (IOCTL_AUO_PREFIX | 0x07) +#define IOCTL_AUO_PROGRESSBAR (IOCTL_AUO_PREFIX | 0x08) +#define IOCTL_AUO_WAITBUSY (IOCTL_AUO_PREFIX | 0x09) /* Command definition * * 3322 2222 2222 1111 1111 1100 0000 0000 * @@ -68,7 +70,7 @@ typedef struct sAUOCommand_t #define SET_AUO_COMMAND SET_AUO_WRITE_COMMAND #define SET_AUO_READ_COMMAND(command, nb_param, have_data, need_wait) SET_AUO_COMMAND_EXT(command, nb_param, have_data, need_wait, 1) -#if (AUO_FIRMWARE_VERSION == 33) /* Command set for TCON firmware v33 */ +#if (AUO_FIRMWARE_VERSION >= 33) /* Command set for TCON firmware v33 and more */ /* Initialisation commands */ #define AUOCMD_INIT_SET SET_AUO_COMMAND(0x0000, 1, 0, 1) @@ -76,7 +78,7 @@ typedef struct sAUOCommand_t #define AUOCMD_VCOM_FRAMERATE SET_AUO_COMMAND(0x0004, 1, 0, 0) /* Power management */ -#define AUOCMD_STANDBY SET_AUO_COMMAND(0x0001, 0, 0, 1) +#define AUOCMD_STANDBY SET_AUO_COMMAND(0x0001, 1, 0, 1) #define AUOCMD_WAKEUP SET_AUO_COMMAND(0x0002, 0, 0, 0) /* Display commands */ @@ -120,7 +122,6 @@ typedef struct sAUOCommand_t #define AUO_DSPPARAM_MODE_TEXT (0x02 << 12) /* Mode 2: Text mode 2bit */ #define AUO_DSPPARAM_MODE_HIGHSPEED (0x03 << 12) /* Mode 3: Highspeed mode 1bit */ #define AUO_DSPPARAM_MODE_HANDWRITE (0x04 << 12) /* Mode 4: Handwriting mode 1bit */ -#define AUO_DSPPARAM_MODE_AUTOSELECT (0x05 << 12) /* Mode 5: Autoselect mode */ /* INIT_SET command parameters */ #define AUO_INITPARAM_OUT_DATA_ARR (0x01 << 5) /* Set to 0 (default) for normal, 1 for inverse byte order */ @@ -145,12 +146,12 @@ typedef struct sAUOCommand_t #define AUO_INITPARAM_DATA_FILTER (0x01 << 12) /* Data filter (1: active, 0: inactive) */ #define AUO_INITPARAM_TEMP_AVERAGE (0x01 << 13) /* Temperature average (1: active, 0: inactive) */ -int Epaper_sendCommand(sAUOCommand *cmd); - /* Please, do not use these #define s */ #define GET_COMMAND_PARAM_NUM(command) ((command >> 20) & 0x0F) #define GET_COMMAND_HAVE_DATA(command) ((command >> 28) & 0x01) #define GET_COMMAND_NEED_WAIT(command) ((command >> 29) & 0x01) #define GET_COMMAND_READ_WRITE(command) ((command >> 30) & 0x01) +#define AUOCMD_EQUAL(c,v) (((c) & 0xFFFF) == ((v) & 0xFFFF)) + #endif /* AUOFB_IOCTL_H */ diff --git a/include/linux/cyevent.h b/include/linux/cyevent.h index 41a8e65..0eca47e 100644 --- a/include/linux/cyevent.h +++ b/include/linux/cyevent.h @@ -1,10 +1,11 @@ // =========================================================================== -// cyio.h +// Cybook Event Manager - cyevent.h // Copyright (C) 2008-2010 Bookeen - All rights reserved // =========================================================================== -#define CYIO_EVENT_VERSION 1 +#define CYEV_CURRENT_VERSION 0x10 /* 1.0 */ +#pragma pack(1) typedef struct sCyEvent_t { unsigned char type; @@ -19,19 +20,26 @@ typedef struct sCyEvent_t unsigned short y1; unsigned short x2; unsigned short y2; - } touch; - struct - { - unsigned char key_ascii; - } key; + unsigned char fingers; + } touch; + unsigned char key; + unsigned char orientation; + unsigned char timer_type; } data; } CyEvent_t; +#pragma pack() + +#define NEW_CYEVENT(evType) { \ + .type = evType, \ + .flags = 0, \ + .version = CYEV_CURRENT_VERSION, \ + .data.raw = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, } enum { CYEVENT_TYPE_KEY = 'k', CYEVENT_TYPE_TOUCH = 't', - CYEVENT_TYPE_ACCEL = 'a', + CYEVENT_TYPE_ORIENTATION = 'o', CYEVENT_TYPE_TIMER = 'z', CYEVENT_TYPE_SYSTEM = 's', //CYIO_EVENT_ = '', @@ -53,42 +61,69 @@ enum #define CYEVENT_KEY_VOLN '-' #define CYEVENT_KEY_TOGGLE_ACCEL 'a' #define CYEVENT_KEY_FACTORY_RESET 'f' +#define CYEVENT_KEY_USB_IN 'p' +#define CYEVENT_KEY_USB_OUT 'P' + +/* Timer event */ +#define CYEVENT_TIMER_SCREEN 's' +#define CYEVENT_TIMER_DEVICE 'd' + /* Flags definitions */ /* Bit 7 to Bit 4 are event type dependent. If the event need more than 4 flags, * it can use it's own "private" values */ - /* Key event flags */ -#define CYEVENT_FLAG_KEY_CONTROL_CHARS (1 << 7) /*** Signal that the current key is not a real key (ie not an ascii value) */ +#define CYEVENT_FLAG_KEY_CONTROL_CHARS (1 << 7) /***< Signal that the current key is not a real key (ie not an ascii value) */ /* Touch event flags */ #define CYEVENT_FLAG_TOUCH_UP (0x1 << 6) #define CYEVENT_FLAG_TOUCH_MOVE (0x2 << 6) #define CYEVENT_FLAG_TOUCH_DOWN (0x3 << 6) +#define CYEVENT_FLASH_TOUCH_MASK (0x3 << 6) +#define CYEVENT_FLAG_TWO_FINGER_DOWN (1 << 5) /* System Event */ -#define CYEVENT_FLAG_USB_STATE (1 << 7) /*** If not set, the USB is unplugged */ -#define CYEVENT_FLAG_AC_STATE (1 << 6) /*** If not set, the AC is unplugged */ -#define CYEVENT_FLAG_AC_STATE (1 << 5) /*** If not set, the SD is unplugged */ - -/* Timer event */ -#define CYEVENT_FLAG_TIMER_SCREEN (1 << 7) -#define CYEVENT_FLAG_TIMER_DEVICE (1 << 6) +#define CYEVENT_FLAG_USB_MESSAGE (0x0 << 6) /***< this is an USB event */ +//#define CYEVENT_FLAG_AC_MESSAGE (0x1 << 6) /***< this is an AC event */ +#define CYEVENT_FLAG_SD_MESSAGE (0x2 << 6) /***< this is a SD event */ +#define CYEVENT_FLAG_SYS_STATUS (1 << 5) /***< this event is a plug (1) or unplug (0) event */ +/* These bits are set by the implementation and should not be touched by the driver / receiver */ /* Bit 3 to Bit 2 are reserved (v1) */ #define CYEVENT_FLAG_ENDOFREPEAT (1 << 1) #define CYEVENT_FLAG_REPEATEVENT (1 << 0) - - +// =========================================================================== +#ifdef __KERNEL__ // =========================================================================== /* Exported function of CyEvent */ - +int CyEvent_PushNewEvent(CyEvent_t *CyEvent, char wantRepeat); +int CyEvent_PushNewUniqueEvent(CyEvent_t *CyEvent); +int CyEvent_PushOrUpdateUniqueEvent(CyEvent_t *CyEvent, char wantRepeat); +int CyEvent_PushOrUpdateUniqueEventFlaged(CyEvent_t *CyEvent, char wantRepeat, unsigned char flagMask); +int CyEvent_InvalidateUniqueEvent(CyEvent_t *CyEvent); +int CyEvent_InvalidateRepeatableEvent(CyEvent_t *CyEvent); +// =========================================================================== +typedef void (*callback_func)(void); +typedef void (*callback2_func)(unsigned char data); +typedef int (*ioctl_func)(unsigned int cmd, unsigned long arg); +typedef struct cyevent_device +{ + callback_func resume, suspend, deepsleep; + callback2_func event_read; + callback_func event_listempty; + ioctl_func ioctl; + unsigned int ioctl_prefix; + unsigned char event_read_listen; /* 0 here mean all events */ +} cyevent_device; +#define NEW_CYDEV() { .resume = NULL, .suspend = NULL, .deepsleep = NULL .ioctl = NULL,\ + .event_listempty = NULL, .event_read = NULL, .event_read_listen = 0, } +#define IOCTL_PFX(c) ((c & 0xFF) << 8) +int CyEvent_RegisterDevice(cyevent_device *dev); +int CyEvent_DeregisterDevice(cyevent_device *dev); +// =========================================================================== +#endif // =========================================================================== - - - - /* TODO: This part should be moved elsewhere... */ // =========================================================================== /* Non directly CyIO related values, but used for the Accelerometer */ @@ -106,3 +141,23 @@ enum CYGSENSOR_STATUS_CRITICALERROR = 6, /** If we are in this status, the G-Sensor is non working: possible cause, defective chip */ CYGSENSOR_STATUS_SUSPENDED = 7, /** The GSENSOR was on, the device go to deepsleep, so we go in this state. */ }; + +#define SET_IOCTL(c, v) (((c & 0xFF) << 8) | (v & 0xFF)) + +#define GET_IOCTL_PREFIX(c) (c & 0xFF00) + +#define CYIO_CTL_LED_CMD SET_IOCTL('C', 'l') +#define CYIO_CTL_USB_STATUS SET_IOCTL('C', 'u') +#define CYIO_CTL_SD_STATUS SET_IOCTL('C', 's') + +#define CYIO_CTL_PWRLED_CHANGE 0x002 +#define CYIO_CTL_WFILED_CHANGE 0x020 +#define CYIO_CTL_BTHLED_CHANGE 0x200 + +#define CYIO_CTL_PWRLED_SETON (CYIO_CTL_PWRLED_CHANGE | 0x001) +#define CYIO_CTL_WFILED_SETON (CYIO_CTL_WFILED_CHANGE | 0x010) +#define CYIO_CTL_BTHLED_SETON (CYIO_CTL_BTHLED_CHANGE | 0x100) + +#define CYIO_CTL_PWRLED_SETOFF (CYIO_CTL_PWRLED_CHANGE | 0x000) +#define CYIO_CTL_WFILED_SETOFF (CYIO_CTL_WFILED_CHANGE | 0x000) +#define CYIO_CTL_BTHLED_SETOFF (CYIO_CTL_BTHLED_CHANGE | 0x000)