Commit for backup purpose
This commit is contained in:
477
drivers/input/cyevent.c
Normal file
477
drivers/input/cyevent.c
Normal file
@@ -0,0 +1,477 @@
|
||||
h
|
||||
// ===========================================================================
|
||||
// cyio.c
|
||||
// Copyright (C) 2008-2010 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 <linux/proc_fs.h>
|
||||
|
||||
#include <asm/arch/regs-gpio.h>
|
||||
#include <asm/arch/regs-gpioj.h>
|
||||
|
||||
#include <cybook.h>
|
||||
|
||||
#include <linux/cyevent.h>
|
||||
|
||||
#define CYEV_MAX_EVENT 20
|
||||
#define CYEV_REPEAT_DELAY (HZ/2); /* ~500ms */
|
||||
#define CYEV_CURRENT_VERSION 0x10 /* 1.0 */
|
||||
enum { INVALID = 0, VALID };
|
||||
|
||||
struct
|
||||
{
|
||||
char valid;
|
||||
char wantRepeat;
|
||||
char seen;
|
||||
char unique;
|
||||
int repeatDelay;
|
||||
CyEvent_t payload;
|
||||
} CyEv_PayList;
|
||||
|
||||
CyEv_PayList *cyev_eventList[CYEV_MAX_EVENT];
|
||||
|
||||
struct task_struct *openingTask = 0;
|
||||
|
||||
/* TODO: Add a locking method for accessing the eventList */
|
||||
|
||||
// ===========================================================================
|
||||
// List management
|
||||
void CyEv_ClearEventList(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < CYEV_MAX_EVENT; i++)
|
||||
{
|
||||
cyev_eventList[i].wantRepeat = false;
|
||||
cyev_eventList[i].seen = false;
|
||||
cyev_eventList[i].unique = false;
|
||||
cyev_eventList[i].repeatDelay = 0;
|
||||
cyev_eventList[i].valid = INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
static int listPos = 0;
|
||||
int i;
|
||||
CyEvent_t ret = NULL;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* 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 (cyev_eventList[i % CYEV_MAX_EVENT].repeatDelay < jiffies) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else /* if (cyev_eventList[i % CYEV_MAX_EVENT].repeatDelay >= jiffies) ) */
|
||||
{
|
||||
/* Set the Repeat flag to true */
|
||||
cyev_eventList[i % CYEV_MAX_EVENT].payload.flags |= CYEVENT_FLAG_REPEATEVENT;
|
||||
}
|
||||
}
|
||||
|
||||
cyev_eventList[i % CYEV_MAX_EVENT].seen = true;
|
||||
|
||||
/* Return the event */
|
||||
ret = &(cyev_eventList[i % CYEV_MAX_EVENT].payload);
|
||||
|
||||
/* If the event is not a repeatable event, invalidate it! */
|
||||
if (cyev_eventList[i % CYEV_MAX_EVENT].wantRepeat == false)
|
||||
{
|
||||
cyev_eventList[i % CYEV_MAX_EVENT].valid = INVALID;
|
||||
}
|
||||
|
||||
/* Update the index for the next element to scan */
|
||||
listPos = (listPos + i + 1) % CYEV_MAX_EVENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret; /* We will return NULL if no valid payload */
|
||||
}
|
||||
|
||||
int isEventNotDuplicate(CyEvent_t *CyEvent)
|
||||
{
|
||||
int i;
|
||||
CyEvent_t *cur:
|
||||
for(i = 0; i < CYEV_MAX_EVENT; i++)
|
||||
{
|
||||
cur = &(cyev_eventList[i].payload);
|
||||
if (cyev_eventList[i].unique == true)
|
||||
{
|
||||
if (cur->type == CyEvent->type) /* To be verified */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int CyEv_AddNewEvent(CyEvent_t *CyEvent, char wantRepeat, char wantUnique)
|
||||
{
|
||||
/* 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.*/
|
||||
|
||||
/* If wantUnique, first check that there is not another unique event */
|
||||
if ((wantUnique) && !isEventNotDuplicate(CyEvent))
|
||||
goto exit;
|
||||
|
||||
/* Scan the list starting from the last position stored */
|
||||
for(i = 0; i < CYEV_MAX_EVENT; i++)
|
||||
{
|
||||
/* Stop on the first "VALID" event */
|
||||
if (cyev_eventList[i].valid == INVALID)
|
||||
{
|
||||
/* Store the event */
|
||||
memcpy(&(cyev_eventList[i].payload), CyEvent, sizeof(CyEvent_t));
|
||||
|
||||
/* Force version in the structure */
|
||||
cyev_eventList[i].payload.version = CYEV_CURRENT_VERSION;
|
||||
cyev_eventList[i].valid = VALID;
|
||||
if (wantUnique)
|
||||
cyev_eventList[i].unique = true;
|
||||
else
|
||||
cyev_eventList[i].unique = false;
|
||||
if (wantRepeat)
|
||||
{
|
||||
cyev_eventList[i].wantRepeat = true;
|
||||
cyev_eventList[i].repeatDelay = jiffies + CYEV_REPEAT_DELAY;
|
||||
}
|
||||
else
|
||||
cyev_eventList[i].wantRepeat = false;
|
||||
|
||||
|
||||
if (openingTask)
|
||||
wake_up_process(openingTask);
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
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 i;
|
||||
int ret = -1;
|
||||
|
||||
/* Search for the event */
|
||||
for(i = 0; i < CYEV_MAX_EVENT; i++)
|
||||
{
|
||||
if ( (cyev_eventList[i].unique == true) &&
|
||||
(cyev_eventList[i].payload.type == CyEvent.type) )
|
||||
{ /* Found it ! Now update the fields */
|
||||
memcpy(&(cyev_eventList[i].payload), CyEvent, sizeof(CyEvent_t));
|
||||
|
||||
if (wantRepeat)
|
||||
{
|
||||
cyev_eventList[i].wantRepeat = true;
|
||||
cyev_eventList[i].repeatDelay = jiffies + CYEV_REPEAT_DELAY;
|
||||
}
|
||||
else
|
||||
cyev_eventList[i].wantRepeat = false;
|
||||
|
||||
if (openingTask)
|
||||
wake_up_process(openingTask);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CyEv_InvalidateRepeatableEvent(CyEvent_t *CyEvent)
|
||||
{
|
||||
int i;
|
||||
int ret = -1;
|
||||
|
||||
/* Search for the event */
|
||||
for(i = 0; i < CYEV_MAX_EVENT; i++)
|
||||
{
|
||||
if ( (cyev_eventList[i].wantRepeat == true) &&
|
||||
(cyev_eventList[i].payload.type == CyEvent.type) )
|
||||
{ /* Found it ! Now update the fields */
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* set the event "end of repeat" flag */
|
||||
cyev_eventList[i].payload.flags |= CYEVENT_FLAG_ENDOFREPEAT;
|
||||
}
|
||||
|
||||
if (openingTask)
|
||||
wake_up_process(openingTask);
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// External event managment
|
||||
int CyEvent_PushNewEvent(CyEvent_t *CyEvent, char wantRepeat)
|
||||
{
|
||||
if (wantRepeat)
|
||||
return CyEv_AddNewEvent(CyEvent, wantRepeat, true);
|
||||
else
|
||||
return CyEv_AddNewEvent(CyEvent, wantRepeat, false);
|
||||
}
|
||||
EXPORT_SYMBOL(CyEvent_PushNewEvent);
|
||||
|
||||
int CyEvent_PushOrUpdateUniqueEvent(CyEvent_t *CyEvent, char wantRepeat)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* For now a simple call to AddNewEvent */
|
||||
ret = CyEv_UpdateUniqueEvent(CyEvent, wantRepeat);
|
||||
|
||||
if (ret != 0) /* The event is not present */
|
||||
ret = CyEv_AddNewEvent(CyEvent, wantRepeat, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(CyEvent_PushOrUpdateUniqueEvent);
|
||||
|
||||
int CyEvent_InvalidateRepeatableEvent(CyEvent_t *CyEvent)
|
||||
{
|
||||
ret = CyEv_InvalidateRepeatableEvent(CyEvent);
|
||||
}
|
||||
EXPORT_SYMBOL(CyEvent_InvalidateRepeatableEvent);
|
||||
|
||||
// ===========================================================================
|
||||
static int ev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* Clear pending event list... */
|
||||
CyEv_ClearEventList();
|
||||
|
||||
return 0;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
static int ev_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* Clear pending event list... */
|
||||
CyEv_ClearEventList();
|
||||
|
||||
return 0;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if ((CyEvent = CyEv_GetNextEvent()) != NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
openingTask = current;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
set_current_state(TASK_RUNNING);
|
||||
openingTask = 0;
|
||||
|
||||
if (signal_pending(current))
|
||||
{
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (CyEvent != NULL)
|
||||
{
|
||||
nRes = copy_to_user(buf, &CyEvent, nBytes);
|
||||
if (!nRes)
|
||||
nRes = nBytes;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
static int ev_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
unsigned long value;
|
||||
switch(cmd)
|
||||
{
|
||||
default:
|
||||
printk(KERN_ERR "Bad IOCTL\n");
|
||||
break;
|
||||
case CYIO_CTL_LED_CMD:
|
||||
DBG("CYIO_CTL_LED_CMD arg[0x%03X]", arg);
|
||||
|
||||
if ((arg & 0x2) && (arg & 0x1)) /* Power LED */
|
||||
{
|
||||
MSG("\n----------------> POWER LED ON\n");
|
||||
//GPH12
|
||||
__raw_writel(__raw_readl(S3C2410_GPHDAT) | (1 << 12), S3C2410_GPHDAT);
|
||||
}
|
||||
else if (arg & 0x2)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// ===========================================================================
|
||||
static struct file_operations s_io_fops =
|
||||
{
|
||||
owner: THIS_MODULE,
|
||||
read: ev_read,
|
||||
ioctl: ev_ioctl,
|
||||
open: ev_open,
|
||||
release: ev_release,
|
||||
};
|
||||
|
||||
gstatic struct miscdevice s_ev_dev =
|
||||
{
|
||||
.minor = 250,
|
||||
.name = "cyio",
|
||||
.fops = &s_ev_fops,
|
||||
};
|
||||
// ===========================================================================
|
||||
// ---------------------------------------------------------------------------
|
||||
static int io_probe(struct platform_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
static int io_remove(struct platform_device *dev)
|
||||
{
|
||||
misc_deregister(&s_ev_dev);
|
||||
return 0;
|
||||
}
|
||||
// --------------------------------------------------------------------------
|
||||
static int io_resume(struct platform_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
static struct platform_driver cyev_driver =
|
||||
{
|
||||
.driver =
|
||||
{
|
||||
.name = "cyevent",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ev_probe,
|
||||
.remove = ev_remove,
|
||||
.suspend = NULL,
|
||||
.resume = ev_resume,
|
||||
};
|
||||
// ---------------------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
static int __init cyEv_init(void)
|
||||
{
|
||||
if (misc_register(&s_ev_dev))
|
||||
return -EBUSY;
|
||||
|
||||
platform_driver_register(&cyev_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
static void __exit cyEv_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&cyev_driver);
|
||||
|
||||
misc_deregister(&s_ev_dev);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
module_init(cyEv_init);
|
||||
module_exit(cyEv_exit);
|
||||
// ---------------------------------------------------------------------------
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Bookeen <developers@bookeen.com>");
|
||||
MODULE_DESCRIPTION("Cybook Event Manager");
|
||||
MODULE_VERSION("3.0");
|
||||
// ===========================================================================
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
#include <linux/cyio.h>
|
||||
|
||||
//#define DEBUG_MESSAGES
|
||||
//#define DEBUG_TRACEFUNC
|
||||
#define DEBUG_MESSAGES
|
||||
#define DEBUG_TRACEFUNC
|
||||
//#define DBG_IRQ
|
||||
|
||||
#define MODULE_NAME "CYB_TILT"
|
||||
@@ -225,20 +225,20 @@ static irqreturn_t orizontilt_interrupt(int irq, void *dev_id)
|
||||
switch(tmpReg)
|
||||
{
|
||||
case 0x00: /* 90 */
|
||||
calcTilt = 90;
|
||||
break;
|
||||
calcTilt = 90;
|
||||
break;
|
||||
|
||||
case 0x02: /* 0 */
|
||||
calcTilt = 0;
|
||||
break;
|
||||
case 0x02: /* 0 */
|
||||
calcTilt = 0;
|
||||
break;
|
||||
|
||||
case 0x01: /* 180 */
|
||||
calcTilt = 180;
|
||||
break;
|
||||
case 0x01: /* 180 */
|
||||
calcTilt = 180;
|
||||
break;
|
||||
|
||||
case 0x03: /* 270 */
|
||||
calcTilt = 270;
|
||||
break;
|
||||
case 0x03: /* 270 */
|
||||
calcTilt = 270;
|
||||
break;
|
||||
}
|
||||
DBG("New Orientation is: %lu", calcTilt);
|
||||
if (calcTilt != OrizonTilt_CurrentDirection)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <cybook.h>
|
||||
#include <linux/cyio.h>
|
||||
|
||||
#define DEBUG_MESSAGES
|
||||
//#define DEBUG_MESSAGES
|
||||
//#define DEBUG_TRACEFUNC
|
||||
|
||||
#define MODULE_NAME "ORIZON-TS"
|
||||
@@ -299,12 +299,13 @@ static int ots_detect (struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
|
||||
|
||||
if ( request_irq(IRQ_EINT2, ots_interrupt, SA_SHIRQ, "orizon_ts", &ots_client) )
|
||||
{
|
||||
printk(KERN_ERR "failed to get interrupt resouce at IRQ_EINT2.\n");
|
||||
goto exit_kfree;
|
||||
}
|
||||
enable_irq_wake(IRQ_EINT2);
|
||||
}
|
||||
|
||||
goto exit;
|
||||
@@ -352,25 +353,45 @@ static int ots_resume (struct device *dev)
|
||||
/******************************************************************************/
|
||||
/********************** Interrupt Related functions ***************************/
|
||||
/******************************************************************************/
|
||||
static int oldX = 0, oldY = 0;
|
||||
|
||||
static void ots_checkWorkFunction (struct work_struct *work)
|
||||
{
|
||||
unsigned long x1, y1, x2, y2;
|
||||
FUNC_IN();
|
||||
|
||||
/* Here do what the interrupt should... (ie read touch values) */
|
||||
x1 = i2c_smbus_read_byte_data(ots_client, 0);
|
||||
x1 |= i2c_smbus_read_byte_data(ots_client, 1) << 8;
|
||||
|
||||
y1 = i2c_smbus_read_byte_data(ots_client, 2);
|
||||
y1 |= i2c_smbus_read_byte_data(ots_client, 3) << 8;
|
||||
/* TODO: I reversed the X / Y axis to match old driver and revese the X value */
|
||||
y1 = i2c_smbus_read_byte_data(ots_client, 0);
|
||||
y1 |= i2c_smbus_read_byte_data(ots_client, 1) << 8;
|
||||
|
||||
x2 = i2c_smbus_read_byte_data(ots_client, 4);
|
||||
x2 |= i2c_smbus_read_byte_data(ots_client, 5) << 8;
|
||||
x1 = i2c_smbus_read_byte_data(ots_client, 2);
|
||||
x1 |= i2c_smbus_read_byte_data(ots_client, 3) << 8;
|
||||
|
||||
y2 = i2c_smbus_read_byte_data(ots_client, 6);
|
||||
y2 |= i2c_smbus_read_byte_data(ots_client, 7) << 8;
|
||||
y2 = i2c_smbus_read_byte_data(ots_client, 4);
|
||||
y2 |= i2c_smbus_read_byte_data(ots_client, 5) << 8;
|
||||
|
||||
DBG("x1: %lu\ty1: %lu\ty1: %lu\ty2: %lu", x1, y1, x2, y2);
|
||||
x2 = i2c_smbus_read_byte_data(ots_client, 6);
|
||||
x2 |= i2c_smbus_read_byte_data(ots_client, 7) << 8;
|
||||
|
||||
DBG("x1: %lu\ty1: %lu\tx2: %lu\ty2: %lu", x1, y1, x2, y2);
|
||||
|
||||
if ((x1 == 0) && (y1 == 0))
|
||||
{ /* We assume that this is a finger up event */
|
||||
if ( Cyio_PushEvent('R', 1) >= 0 )
|
||||
{
|
||||
Cyio_PushEvent((oldX >> 8) & 0xFF, 0);
|
||||
Cyio_PushEvent((oldX >> 0) & 0xFF, 0);
|
||||
Cyio_PushEvent((oldY >> 8) & 0xFF, 0);
|
||||
Cyio_PushEvent((oldY >> 0) & 0xFF, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oldX = 600 - x1;
|
||||
oldY = y1;
|
||||
}
|
||||
|
||||
/* Say I get the data */
|
||||
ots_ackInterrupt();
|
||||
|
||||
Reference in New Issue
Block a user