Add preliminary support for CyIO/BooEvent

This commit is contained in:
mlt 2009-12-18 18:29:29 +00:00 committed by Godzil
parent 76f20f4d40
commit 6a09ec6d7a
15 changed files with 111641 additions and 28806 deletions

View File

@ -19,3 +19,4 @@ obj-$(CONFIG_S3C2416_PM) += pm.o
# Machine support # Machine support
obj-$(CONFIG_MACH_SMDK2416) += mach-smdk2416.o obj-$(CONFIG_MACH_SMDK2416) += mach-smdk2416.o
obj-$(CONFIG_MACH_SMDK2416) += qisda-utils.o

View File

@ -0,0 +1,32 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/arch/fb.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/udc.h>
#include <asm/arch/l3.h>
#include <asm/arch/audio.h>
#include <asm/arch/buttons.h>
#include "devs.h"
#include "cpu.h"
struct platform_device s3c_device_cyio = {
.name = "cyio2",
.id = -1,
};
EXPORT_SYMBOL(s3c_device_cyio);

View File

@ -0,0 +1,166 @@
/*
* qisda-utils.c
*
* Copyright 2009 Bookeen/Qisda
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/irq.h>
#include <asm/arch/regs-irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/arch/regs-udc-hs.h>
#include <asm/arch/regs-s3c2416-clock.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/setup.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-mem.h>
#include <asm/plat-s3c24xx/s3c2410.h>
#include <asm/plat-s3c24xx/s3c2440.h>
#include <asm/plat-s3c24xx/clock.h>
#include <asm/plat-s3c24xx/devs.h>
#include <asm/plat-s3c24xx/cpu.h>
#include <asm/plat-s3c24xx/common-smdk.h>
int charging_source = 3;
EXPORT_SYMBOL(charging_source);
/* Qisda, ShiYong Lin, 2009/09/10, Detect insertion source {*/
/*Leo*/
int IsWallCharger(void)
{
/*u32 i=0;*/
/*u32 i=0;*/
u32 read_pin=99;/*, test_pin = 99;*/
udelay(1000);
if((readl(S3C2410_GPGDAT)&0x2)==0x2){
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 1); /* usb power enbale */
s3c2410_gpio_cfgpin(S3C2410_GPD13, S3C2410_GPD13_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD13,1); /* usb power enbale */
/* if reset by sleep wakeup, control the retention I/O cell */
if (__raw_readl(S3C_RSTSTAT) & 0x8)
__raw_writel(__raw_readl(S3C_RSTCON)|(1<<16), S3C_RSTCON);
__raw_writel(__raw_readl(S3C2410_MISCCR)&~(1<<12), S3C2410_MISCCR);
__raw_writel(__raw_readl(S3C_PWRCFG)|(1<<4), S3C_PWRCFG);
__raw_writel((0<<2)|(1<<0), S3C_URSTCON);
udelay(1000);
__raw_writel((1<<2)|(0<<0), S3C_URSTCON);
__raw_writel((0<<2)|(0<<0), S3C_URSTCON);
__raw_writel((0<<3)|(0<<2)|(0<<1)|(0<<0), S3C_PHYCTRL);
__raw_writel((1<<31)|(0<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0), S3C_PHYPWR);
__raw_writel((0<<31)|(1<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
__raw_writel((1<<31)|(1<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
read_pin = __raw_readl(S3C_UDC_SYS_STATUS_REG)&0x60;
if(read_pin !=0x60){
// printk("usb\n");
#if defined(CONFIG_QISDA_E600_EVT2)|| defined(CONFIG_QISDA_QD060N00_DVT1_1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
if((readl(S3C2410_GPHDAT) &&(1<<11))==0)
{
printk("3G Module off\n");
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
}
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
#if defined(CONFIG_QISDA_AS090B00_EVT1)||defined(CONFIG_QISDA_AS090B00_EVT1_1)||defined(CONFIG_QISDA_QD090B00_EVT1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
if((readl(S3C2410_GPHDAT) &(1<<11))==0)
{
// printk("3G Module off\n");
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
}
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
return 0;
}
else
{
// printk("wall charger\n");
#if defined(CONFIG_QISDA_E600_EVT2)||defined(CONFIG_QISDA_QD060N00_DVT1_1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
#if defined(CONFIG_QISDA_AS090B00_EVT1)||defined(CONFIG_QISDA_AS090B00_EVT1_1)||defined(CONFIG_QISDA_QD090B00_EVT1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
if((readl(S3C2410_GPHDAT) &(1<<11))==0)
{
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
}
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
return 1;
}
}
/*Leo*/
/* } Qisda, ShiYong Lin, 2009/09/10, Detect insertion source */
EXPORT_SYMBOL(IsWallCharger);

1588
cybook.config Normal file

File diff suppressed because it is too large Load Diff

View File

@ -324,7 +324,9 @@ static int s3c_adc_ioctl(struct inode *inode, struct file *file,
wkup_srce = (unsigned long) arg; wkup_srce = (unsigned long) arg;
printk("Wakeup parameter = %d\n", wkup_srce); printk("Wakeup parameter = %d\n", wkup_srce);
/* Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep {*/ /* Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep {*/
#ifdef QISDA
s3c_keypad_pm_sleep_message_to_ap(1); s3c_keypad_pm_sleep_message_to_ap(1);
#endif
/* } Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep */ /* } Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep */
ret = 0; ret = 0;
break; break;

View File

@ -248,4 +248,10 @@ config KEYPAD_S3C_QISDA
tony.yc.huang@qisda.com tony.yc.huang@qisda.com
#Qisda Tony 090324, add keypad ] #Qisda Tony 090324, add keypad ]
config CYBOOK_CYIO
tristate "CYBOOK buttons"
default y
help
To compile this driver as a module, choose M here.
endif endif

View File

@ -23,3 +23,4 @@ obj-$(CONFIG_KEYPAD_S3C) += s3c-keypad.o
#Qisda Tony 090324, add keypad [ #Qisda Tony 090324, add keypad [
obj-$(CONFIG_KEYPAD_S3C_QISDA) += s3c-keypad-qisda.o obj-$(CONFIG_KEYPAD_S3C_QISDA) += s3c-keypad-qisda.o
#Qisda Tony 090324, add keypad ] #Qisda Tony 090324, add keypad ]
obj-$(CONFIG_CYIO) += cyio.o

View File

@ -0,0 +1,940 @@
// ===========================================================================
// cyio.c
// Copyright (C) 2008-2009 Bookeen - All rights reserved
// ===========================================================================
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <cybook.h>
#include "cyio.h"
//#define CYIO_TIMER
#define CYIO_REPEAT
#define CYIO_ALTERNATE_KEY
#define DEBUG_MESSAGES
#define DBG_IRQ
#include <asm/hardware.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm-arm/irq.h>
#include <asm/arch/gpio.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm-arm/arch-s3c2410/irqs.h>
#include <asm-arm/arch-s3c2410/gpio.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
// ===========================================================================
spinlock_t io_lock = SPIN_LOCK_UNLOCKED;
static unsigned long io_status = 0;
struct task_struct *ptsk = 0;
unsigned int platform_type = CYBOOK_GEN4;
#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;
static int timer_inited = 0;
static int timer_run = 0;
#endif
#define TRUE (1==1)
#define FALSE (0==1)
#define PFX "CyIO:"
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;
typedef struct _cyEvent_
{
u8 nCode;
u8 nKeyEvent;
void* pNext;
} cyEvent;
static cyEvent s_nEvents[10];
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
#define GPIO_F0 S3C2410_GPF0
#define GPIO_F1 S3C2410_GPF1
#define GPIO_F2 S3C2410_GPF2
#define GPIO_F3 S3C2410_GPF3
#define GPIO_F4 S3C2410_GPF4
#define GPIO_F5 S3C2410_GPF5
#define GPIO_F6 S3C2410_GPF6
#define GPIO_F7 S3C2410_GPF7
#define GPIO_F8 S3C2410_GPF8
#define GPIO_F9 S3C2410_GPF9
#define GPIO_F10 S3C2410_GPF10
#define GPIO_G0 S3C2410_GPG0
#define GPIO_G1 S3C2410_GPG1
#define GPIO_G2 S3C2410_GPG2
#define GPIO_G3 S3C2410_GPG3
#define GPIO_G4 S3C2410_GPG4
#define GPIO_G5 S3C2410_GPG5
#define GPIO_G6 S3C2410_GPG6
#define GPIO_G7 S3C2410_GPG7
#define GPIO_G8 S3C2410_GPG8
#define GPIO_G9 S3C2410_GPG9
static cyIrq *s_nIrq ;
static int nCnt;
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_EINT1, GPIO_F1, 0, 0, 0, CYEVENT_SD_IN, CYEVENT_SD_OUT, 0, "SD Card" } //1
//, { IRQ_EINT2, GPIO_F2, 0, 0, 0, CYEVENT_TP_PRESS, CYEVENT_TP_REL, 0, "Touch Panel" } //2
//
/* EINT3 is not Wifi EINT */
/* EINT4 is Headphone plug status */
/* EINT5 is Touchpanel Enable */
/* EINT6 is charger status */
, { IRQ_EINT7, GPIO_F7, 0, 1, 0, CYEVENT_KEY_LEFT, 0, 0, "Left" } //3
/* INT8 is Power Keey???? */
//, { IRQ_EINT9, GPIO_G1, 0, 0, 0, CYEVENT_USB_IN, CYEVENT_USB_OUT, 0, "USB" } //4
/* EINT10 is SD power enable */
, { IRQ_EINT15, GPIO_G7, 0, 1, 0, CYEVENT_KEY_RIGHT, 0, 0, "Right" } //5
/* 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 u8* s_pbUsbPowered = NULL;
static u8* s_pbAcPowered = 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);
#endif
#undef MSG
#undef DBG
#ifdef DEBUG_MESSAGES
#define MSG(str) { printk(KERN_ALERT str "\n"); }
#define DBG(str, ...) { printk(KERN_ALERT str "\n", __VA_ARGS__); }
#else
#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 */
void Cyio_PushEvent(char eventId, char unique)
{
cyEvent *pEventC;
spinLock(&io_lock);
if (unique != 0)
{
pEventC = s_pEventR;
do
{
if (pEventC->nCode == eventId)
goto exit;
pEventC = pEventC->pNext;
} while ((pEventC != s_pEventW) && (s_pEventR != s_pEventW));
}
DBG("New Pushed event '%c'\n", eventId);
if (s_pEventW)
{
++s_nEventCnt;
s_pEventW->nCode = eventId;
s_pEventW->nKeyEvent = 0;
s_pEventW = s_pEventW->pNext;
}
spinUnlock(&io_lock);
exit:
if (ptsk)
wake_up_process(ptsk);
}
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; i<s_nEventMax; ++i)
{
cyEvent* pEvent = &s_nEvents[i];
pEvent->nCode = 0;
pEvent->nKeyEvent = 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)
{
int i;
cyIrq *pIrq, *pIrq0;
int ret;
pIrq0 = &s_nIrq[0];
// Read state as fast as possible (important when resuming)
for (i=0, pIrq=pIrq0; i<nCnt; ++i, ++pIrq)
{
#if 1
pIrq->bActive = !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
}
// Preparatory pass
for (i=0, pIrq=pIrq0; i<nCnt; ++i, ++pIrq)
{
switch (pIrq->nCodeActive)
{
case CYEVENT_USB_IN:
s_pbUsbPowered = &pIrq->bActive;
s_pbAcPowered = &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 = 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; i<nCnt; ++i, ++pIrq)
{
if (!pIrq->bActive && 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 = s_pEventW->pNext;
}
}
spinUnlock(&io_lock);
}
for (i=0, pIrq=pIrq0; i<nCnt; ++i, ++pIrq)
{
int nIrq = pIrq->nIrq;
set_irq_type(nIrq, IRQT_BOTHEDGE);
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, "cyio", pIrq);
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;
#endif
}
// ---------------------------------------------------------------------------
void io_deinitIrq(void)
{
int i;
cyIrq *pIrq, *pIrq0;
#ifdef CYIO_TIMER
del_timer(&io_timer);
timer_run = 0;
#endif
//nCnt = sizeof(s_nIrq)/sizeof(s_nIrq[0]);
pIrq0 = &s_nIrq[0];
for (i=0, pIrq=pIrq0; i<nCnt; ++i, ++pIrq)
free_irq(pIrq->nIrq, pIrq);
}
// ---------------------------------------------------------------------------
//#define DBG_IRQ
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
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);
#endif
blCodeActive = (s_altKeyPress && pIrq->bKeyIrq) ? pIrq->nCodeAlternate : (bActive ? pIrq->nCodeActive : pIrq->nCodeInactive);
#ifdef CYIO_ALTERNATE_KEY
if (s_altKeyPresent)
{
s_altKeyPress = !gpio_get_value(s_altKeyGpio);
DBG("alt status: %d", s_altKeyPress);
}
#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 = 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 = 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 = s_pEventW->pNext;
}
spinUnlock(&io_lock);
}
if (ptsk)
wake_up_process(ptsk);
return IRQ_HANDLED;
}
// ---------------------------------------------------------------------------
#ifdef CYIO_TIMER
static void io_timer_handler(unsigned long nData)
{
/* YEP inside */
#if 0
//#ifdef G_SENSOR
if (hold_wakeup==1) {
del_timer(&io_timer);
goto end_timer;
}
#endif
/* end YEP inside */
DBG("Timer [%ld] tick...\n", nData);
spin_lock_irq(&io_lock);
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 = 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;
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;
s_pEventR->nCode = 0;
--s_nEventCnt;
if (s_pEventR->nKeyEvent)
{
--s_nKeyLogCnt;
#ifdef CYIO_REPEAT
if (nData != CYEVENT_KEY_OFF)
{
DBG("(line %d)Set s_nPrevKey", __LINE__);
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];
MSG("Will test key...");
for (i=0, pIrq=pIrq0; i<nCnt; ++i, ++pIrq)
{
#ifdef CYIO_ALTERNATE_KEY
if ((pIrq->nCodeActive != s_nPrevKey) && (pIrq->nCodeAlternate != s_nPrevKey))
#else
if (pIrq->nCodeActive != s_nPrevKey)
#endif
{
MSG("!CodeActive and Alt+!AltCode");
continue;
}
MSG("May clear prevkey");
if (!pIrq->bActive || gpio_get_value(pIrq->nGpio))
{
DBG("(line %d)Set s_nPrevKey", __LINE__);
s_nPrevKey = 0;
}
break;
}
if (s_nPrevKey)
{
MSG("Will Set Repeat flag...");
nData = s_nPrevKey | CYEVENT_KEY_REPEAT_FLAG;
s_bRepMode = 1;
}
}
#endif
spinUnlock(&io_lock);
if (nData != 0)
{
#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_pbAcPowered && !(*s_pbUsbPowered) && !(*s_pbAcPowered))
{
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)
{
nRes = copy_to_user(buf,&nData,nBytes);
if (!nRes)
nRes = nBytes;
}
return nRes;
}
// ---------------------------------------------------------------------------
static int io_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}
// ===========================================================================
static struct file_operations s_io_fops =
{
owner: THIS_MODULE,
read: io_read,
ioctl: io_ioctl,
open: io_open,
release: io_release,
};
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)
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("<<Resume() .......\n");
return 0;
}
// ---------------------------------------------------------------------------
static struct platform_driver cyio_driver =
{
.driver =
{
.name = "cyio",
.owner = THIS_MODULE,
},
.probe = io_probe,
.remove = io_remove,
.suspend = NULL,
.resume = io_resume,
};
// ---------------------------------------------------------------------------
// ===========================================================================
static int __init cyIo_init(void)
{
#if 0
if(platform_type == CYBOOK_OPUS)
{
s_nIrq = s_nIrq_OPUS;
nCnt = sizeof(s_nIrq_OPUS)/sizeof(s_nIrq_OPUS[0]);
}
else if (/* GEN3 && GEN3GOLD */
{
s_nIrq = s_nIrq_GEN3;
nCnt = sizeof(s_nIrq_GEN3)/sizeof(s_nIrq_GEN3[0]);
}
#endif
s_nIrq = s_nIrq_GEN4;
nCnt = sizeof(s_nIrq_GEN4)/sizeof(s_nIrq_GEN4[0]);
DBG("s_nEventMax:%d, s_nEventCnt:%d, s_nKeyLogMax:%d, s_nKeyLogCnt:%d",s_nEventMax,s_nEventCnt,s_nKeyLogMax,s_nKeyLogCnt);
/* end YEP inside */
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");
}
// ---------------------------------------------------------------------------
module_init(cyIo_init);
module_exit(cyIo_exit);
// ---------------------------------------------------------------------------
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Bookeen <developers@bookeen.com>");
MODULE_DESCRIPTION("Cybook Event Manager");
MODULE_VERSION("3.0");
// ===========================================================================

View File

@ -0,0 +1,65 @@
// ===========================================================================
// cyio.h
// Copyright (C) 2008-2009 Bookeen - All rights reserved
// ===========================================================================
// Key events
#define CYEVENT_KEY_ENTER 'e'
#define CYEVENT_KEY_RIGHT 'r'
#define CYEVENT_KEY_DOWN 'd'
#define CYEVENT_KEY_LEFT 'l'
#define CYEVENT_KEY_UP 'u'
#define CYEVENT_KEY_F1 '1'
#define CYEVENT_KEY_F2 '2'
#define CYEVENT_KEY_F3 '3'
#define CYEVENT_KEY_F4 '4'
#define CYEVENT_KEY_OFF 'o'
#define CYEVENT_KEY_VOLP '+'
#define CYEVENT_KEY_VOLN '-'
#define CYEVENT_KEY_REPEAT_FLAG 0x80
#define CYEVENT_KEY_REPEAT_END '0'
// Physical events
#define CYEVENT_USB_IN 'p'
#define CYEVENT_USB_OUT 'q'
#define CYEVENT_AC_IN 'a'
#define CYEVENT_AC_OUT 'b'
#define CYEVENT_ACN_IN 'j'
#define CYEVENT_ACN_OUT 'k'
#define CYEVENT_SD_IN 's'
#define CYEVENT_SD_OUT 't'
#define CYEVENT_SDN_IN 'u'
#define CYEVENT_SDN_OUT 'v'
// G-Sensor events
#define CYEVENT_ORIENTATIONCHANGED 'O'
#define CYEVENT_G_ROT000 'A'
#define CYEVENT_G_ROT090 'B'
#define CYEVENT_G_ROT180 'C'
#define CYEVENT_G_ROT270 'D'
#define CYEVENT_TOGGLE_GSENSOR 'G'
// Logical events
// CYEVENT_KEY_OFF + CYEVENT_KEY_VOLN
#define CYEVENT_FACTORY_OFF 'x'
#define CYEVENT_SUSPEND_SCREEN 'y'
#define CYEVENT_SUSPEND_DEVICE 'z'
// ===========================================================================
/* YEP inside */
#define CYIO_KERNEL_2_6 1
#define G_SENSOR_ON '1'
#define G_SENSOR_OFF '0'
#define G_SENSOR_CAL 'C'
/* end YEP inside */
enum
{
CYGSENSOR_STATUS_ENABLED = 0,
CYGSENSOR_STATUS_DISABLED = 1,
CYGSENSOR_STATUS_NOTCALIB = 2, /* Not calibrated, or invalid calibration data */
CYGSENSOR_STATUS_CALIBRATED = 3, /* This status should never been read, but it could help to debug */
CYGSENSOR_STATUS_UNKNOWN = 4, /* This status should not been read too, but it could help to debug */
};
/* Exported function of CyIO */
void Cyio_ResetTimer(void);
void Cyio_PushEvent(char eventId, char unique);

View File

@ -48,7 +48,9 @@ static unsigned int tick_count;
/* Qisda, ShiYong Lin, 2009/07/22, Implement function for RTC tick service {*/ /* Qisda, ShiYong Lin, 2009/07/22, Implement function for RTC tick service {*/
static unsigned long uiResolution = 0; static unsigned long uiResolution = 0;
#ifdef QISDA
extern void rtc_tick_keypad_message_to_ap (void); extern void rtc_tick_keypad_message_to_ap (void);
#endif
/* Qisda, ShiYong Lin, 2009/07/22, Implement function for RTC tick service }*/ /* Qisda, ShiYong Lin, 2009/07/22, Implement function for RTC tick service }*/
static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
@ -67,8 +69,9 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
{ {
struct rtc_device *rdev = id; struct rtc_device *rdev = id;
#ifdef QISDA
rtc_tick_keypad_message_to_ap(); rtc_tick_keypad_message_to_ap();
#endif
rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF); rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF);
#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) #if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410)

View File

@ -128,7 +128,9 @@ static void reconfig_usbd(void);
/*send key code F6 1 when USB plugin*/ /*send key code F6 1 when USB plugin*/
/*send key code F6 0 when USB unplugin*/ /*send key code F6 0 when USB unplugin*/
/*send key code F6 0 when USB safety remove USB{*/ /*send key code F6 0 when USB safety remove USB{*/
void USB_SaftRemove_keypad_message_to_ap(uint uiSleep); #ifdef QISDA
void USB_SaftRemove_keypad_message_to_ap(uint uiSleep)
#endif
/*}Qisda,Leo SJ Yang,2009/10/26*/ /*}Qisda,Leo SJ Yang,2009/10/26*/
static __inline__ u32 usb_read(u32 port, u8 ind) static __inline__ u32 usb_read(u32 port, u8 ind)
{ {
@ -1125,8 +1127,10 @@ static irqreturn_t s3c_udc_irq(int irq, void *_dev)
/*send key code F6 0 when USB safety remove USB{*/ /*send key code F6 0 when USB safety remove USB{*/
/*Qisda,Leo SJ Yang,2009/11/13*/ /*Qisda,Leo SJ Yang,2009/11/13*/
/*prevent from sending saftremove event to MMI when the event to be occured is not the action of saftremove{*/ /*prevent from sending saftremove event to MMI when the event to be occured is not the action of saftremove{*/
#ifdef QISDA
if((intr_status&S3C_UDC_INT_VBUSON)==0) if((intr_status&S3C_UDC_INT_VBUSON)==0)
USB_SaftRemove_keypad_message_to_ap(0); USB_SaftRemove_keypad_message_to_ap(0);
#endif
/*}Qisda,Leo SJ Yang,2009/11/13*/ /*}Qisda,Leo SJ Yang,2009/11/13*/
#endif #endif
/*}Qisda,Leo SJ Yang,2009/08/26 set g_EMUSBTestIsOK=0 when uplug USB*/ /*}Qisda,Leo SJ Yang,2009/08/26 set g_EMUSBTestIsOK=0 when uplug USB*/
@ -1793,8 +1797,9 @@ static void s3c_ep0_setup(struct s3c_udc *dev, u32 csr)
/*Qisda,Leo SJ Yang,2009/07/28 add /proc/driver/udc for EM mode{*/ /*Qisda,Leo SJ Yang,2009/07/28 add /proc/driver/udc for EM mode{*/
#ifdef CONFIG_USB_GADGET_DEBUG_FILES #ifdef CONFIG_USB_GADGET_DEBUG_FILES
g_EMUSBTestIsOK=1; g_EMUSBTestIsOK=1;
#ifdef QISDA
USB_SaftRemove_keypad_message_to_ap(1); USB_SaftRemove_keypad_message_to_ap(1);
#endif
#endif #endif
/*}Qisda,Leo SJ Yang,2009/07/28 add /proc/driver/udc for EM mode*/ /*}Qisda,Leo SJ Yang,2009/07/28 add /proc/driver/udc for EM mode*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

19
include/cybook.h Normal file
View File

@ -0,0 +1,19 @@
/*
* Disclaimer (blabla)
*
* Author: Manoël Trapier <manoelt@bookeen.com>
* Copyright (c) 2009 Bookeen
*
*/
#ifndef CYBOOK_H
#define CYBOOK_H
enum {
CYBOOK_GEN3 = 0,
CYBOOK_OPUS,
CYBOOK_GEN3GOLD,
CYBOOK_GEN4,
};
extern unsigned int platform_type;
#endif /* CYBOOK_H */

View File

@ -254,7 +254,9 @@ static int enter_pm_cpu_mode(suspend_state_t state)
Unlock: Unlock:
mutex_unlock(&pm_mutex); mutex_unlock(&pm_mutex);
/* Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep {*/ /* Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep {*/
#ifdef QISDA
s3c_keypad_pm_sleep_message_to_ap(0); s3c_keypad_pm_sleep_message_to_ap(0);
#endif
// printk(KERN_ERR "Sleep end enter_pm_cpu_mode, %d\n", state); // printk(KERN_ERR "Sleep end enter_pm_cpu_mode, %d\n", state);
/* } Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep */ /* } Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep */
return error; return error;
@ -299,7 +301,9 @@ static int enter_state(suspend_state_t state)
Unlock: Unlock:
mutex_unlock(&pm_mutex); mutex_unlock(&pm_mutex);
/* Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep {*/ /* Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep {*/
#ifdef QISDA
s3c_keypad_pm_sleep_message_to_ap(0); s3c_keypad_pm_sleep_message_to_ap(0);
#endif
/* } Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep */ /* } Qisda, ShiYong Lin, 2009/09/28, Add the sleep event message when sleep */
return error; return error;
} }