2.6.36的内核改了些细节,对应的触摸屏驱动也改了些,下面是最新源码:
/* skyeye_ts_drv.h */
/*----------------------------------------------------------------------------*/
/* $Id: mc68328digi.h,v 1.1 2003/03/06 10:37:43 davidm Exp $
*
* linux/drivers/char/mc68328digi.h - Touch screen driver.
* Header file.
*
* Author: Philippe Ney <[email protected]>
* Copyright (C) 2001 SMARTDATA <www.smartdata.ch>
*
* 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, or (at your option) any later version.
*
* 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.
*
* Thanks to:
* Kenneth Albanowski for is first work on a touch screen driver.
* Alessandro Rubini for is "Linux device drivers" book.
* Ori Pomerantz for is "Linux Kernel Module Programming" guide.
*
* Updates:
* 2001-03-12 Pascal bauermeister
* - Modified the semantics of ts_drv_params;
* - Added check for version in ioctl()
* - included a sample code in the end of this file as comment
*
*----------------------------------------------------------------------------
* Known bugs:
* - read() returns zero
*
*----------------------------------------------------------------------------
* HOW TO SETUP THE PARAMETERS FOR COORDINATES SCALING
*
* The driver does scaling as follows, in this order:
* o for x and y raw samples:
* - raw position is multiplied by ratio_num
* - result is divided by ratio_den
* - offset is added to the result
* - result is bounded by min and max
* o x and y results are swapped if xy_swap is non-zero
*
* Appropriate parameter combinations allow things like:
* o rotations in multiples of 90 degrees
* o coordinate mirroring
* o negative coordinates
* o etc.
*
* How to calculate the parameters:
* o Depending on your hardware, you may need to have x and y swapped. If
* so, set xy_swap to 1, always.
* o Calibration phase:
* choose two physical points, preferrably diagonally opposite corners of
* the touch panel. Measure one first time with num=den=1 and offset=0,
* i.e. do an ioctl() to set these parameters, and some read() to read
* these points.
*
* o Let mx1 be the value measured at the left edge of your touchscreen
* mx2 be the value measured at the right edge of your touchscreen
* ux1 be the value you want your userland programs to see for mx1
* ux2 be the value you want your userland programs to see for mx2
* o For X, calculate:
* x_ratio_num = ux1 - ux2
* x_ratio_den = mx1 - mx2
* x_offset = ux1 - mx1*x_ratio_num/x_ratio_den (or the same with x2)
* o Do the same for Y
* o Then set the min and max according to the bounds you desire for userland
* values
*
* Notes:
* o We assume linearity between the touchscreen coordinates space and the
* userland coordinate space
* o During calibration, the points may be any pair of points, but best
* results are obtained if they are as distant as possible
*
*
*----------------------------------------------------------------------------
*
* Event generated:
* __________ ______________
* 1) /PENIRQ | |
* -------
*
* | |
* | +-> generate PEN_UP
* |
* +-------> generate PEN_DOWN
*
* __________ ______________
* 2) /PENIRQ | |
* ------#####-----
*
* | ||||| |
* | ||||| +-> generate PEN_UP
* | |||||
* | ||||+------> generate PEN_MOVE
* | |||+-------> generate PEN_MOVE
* | ||+--------> generate PEN_MOVE
* | |+---------> generate PEN_MOVE
* | +----------> generate PEN_MOVE
* |
* -----------------> generate PEN_DOWN
*
*/
/*----------------------------------------------------------------------------*/
#ifndef _MC68328DIGI_H
#define _MC68328DIGI_H
#ifdef __KERNEL__
#include <linux/time.h> /* for timeval struct */
#include <linux/ioctl.h> /* for the _IOR macro to define the ioctl commands */
#endif
/*----------------------------------------------------------------------------*/
/* Used to check the driver vs. userland program.
*
* If they have the same number, it means that 'struct ts_pen_info' and
* 'struct ts_drv_params' have compatible semantics on both side. Otherwise
* one side is outdated.
*
* The number has to be incremented if and only if updates in the driver lead
* to any change in the semantics of these interface data structures (and not
* if some internal mechanism of the driver are changed).
*/
#define MC68328DIGI_VERSION 2
/* Userland programs can get this version number in params.version after
* ioctl(fd, TS_PARAMS_GET, ¶ms). Userland programs must specify their
* version compatibility by setting version_req to MC68328DIGI_VERSION before
* doing ioctl(fd, TS_PARAMS_SET, ¶ms).
*
* If version_req does not match, ioctl(fd, TS_PARAMS_SET, ¶ms) would return
* EBADRQC ('Invalid request code').
*
* Note:
* it is not possible to check the compatibility for 'struct ts_pen_info'
* without doing an ioctl(fd, TS_PARAMS_SET, ¶ms). So, please, do an
* ioctl(fd, TS_PARAMS_SET, ¶ms)!
*/
/*----------------------------------------------------------------------------*/
/* Pen events */
/* Pen events */
//#define EV_PEN_DOWN 0
#define EV_PEN_DOWN 1
//#define EV_PEN_UP 1
#define EV_PEN_UP 0
#define EV_PEN_MOVE 2
/* Pen states */
/* defined through the 2 lsb of an integer variable. If an error occure,
* the driver will recover the state PEN_UP and the error bit will be set.
*/
//#define ST_PEN_DOWN (0<<0) /* bit 0 at 0 = the pen is down */
#define ST_PEN_DOWN (1<<0) /* bit 1 at 0 = the pen is down */
//#define ST_PEN_UP (1<<0) /* bit 0 at 1 = the pen is up */
#define ST_PEN_UP (0<<0) /* bit 0 at 1 = the pen is up */
#define ST_PEN_ERROR (1<<1) /* bit 1 at 1 means that an error occure */
/* Definition for the ioctl of the driver */
/* Device is type misc then major=10 */
#define MC68328DIGI_MAJOR 10
#define TS_PARAMS_GET _IOR(MC68328DIGI_MAJOR, 0, struct ts_drv_params)
#define TS_PARAMS_SET _IOR(MC68328DIGI_MAJOR, 1, struct ts_drv_params)
/*----------------------------------------------------------------------------*/
/* Available info from pen position and status */
struct ts_pen_info {
int x,y; /* pen position */
int dx,dy; /* delta move from last position */
int event; /* event from pen (DOWN,UP,CLICK,MOVE) */
int state; /* state of pen (DOWN,UP,ERROR) */
int ev_no; /* no of the event */
unsigned long ev_time; /* time of the event (ms) since ts_open */
};
/* Structure that define touch screen parameters */
struct ts_drv_params {
int version; /* version number for check, returned by TS_PARAMS_GET
*/
int version_req; /* version number for check, that MUST be set to
* MC68328DIGI_VERSION prior to do TS_PARAMS_SET,
* or to -1 to bypass checking (do not do this usually)
*/
int x_ratio_num; /* */
int x_ratio_den; /* */
int y_ratio_num; /* */
int y_ratio_den; /* */
int x_offset; /* */
int y_offset; /* */
int xy_swap; /* */
int x_min; /* */
int y_min; /* */
int x_max; /* */
int y_max; /* */
int mv_thrs; /* minimum delta move to considere the pen start to move */
int follow_thrs; /* minimum delta move to follow the pen move when the pen
* is moving
*/
int sample_ms; /* time between sampling (ms) */
int deglitch_on; /* whether to filter glitches at pen down */
int event_queue_on; /* switch on and off the event queue */
};
/*------------------------------------------------------------------------------
** The following sample code illustrates the usage of the ts driver:
**
** #include <string.h>
** #include <errno.h>
** #include <fcntl.h>
** #include <stdio.h>
** #include <linux/mc68328digi.h>
**
**
**
**
** const char *ts_device_name = "/dev/ts";
**
**
**
**
**
**
** void tsdrv_params_fprint(FILE *f, struct ts_drv_params *p)
** {
** fprintf(f, "version : %d/n", p->version);
** fprintf(f, "version_req : %d/n", p->version_req);
** fprintf(f, "x ratio : %d/%d/n", p->x_ratio_num, p->x_ratio_den);
** fprintf(f, "y ratio : %d/%d/n", p->y_ratio_num, p->y_ratio_den);
** fprintf(f, "x limits : %d/%d/n", p->x_min, p->x_max);
** fprintf(f, "y limits : %d/%d/n", p->y_min, p->y_max);
** fprintf(f, "x offset : %d/n", p->x_offset);
** fprintf(f, "y offset : %d/n", p->y_offset);
** fprintf(f, "invert xy : %d/n", p->xy_swap);
** fprintf(f, "mv thrs : %d/n", p->mv_thrs);
** fprintf(f, "follow thrs : %d/n", p->follow_thrs);
** fprintf(f, "sample ms : %d/n", p->sample_ms);
** fprintf(f, "dglitch on : %d/n", p->deglitch_on);
** fprintf(f, "evt Q on : %d/n", p->event_queue_on);
** }
**
**
** int tsdrv_init(int argc, char *argv[])
** {
** int ts_fd;
** int err;
** struct ts_drv_params drv_params;
** int mx1, mx2, my1, my2;
** int ux1, ux2, uy1, uy2;
**
** ts_fd = open(ts_device_name, O_RDWR);
** if(ts_fd==0) {
** fprintf(stderr, "%s: error: could not open device %s/n",
** argv[0], ts_device_name);
** return 0;
** }
**
** err = ioctl(ts_fd, TS_PARAMS_GET, &drv_params);
** if(err) {
** fprintf(stderr, "%s: ioctl TS_PARAMS_GET error: %s/n",
** argv[0], strerror(errno));
** close(ts_fd);
** return 0;
** }
**
** printf("/nDefault driver settings:/n");
** tsdrv_params_fprint(stdout, &drv_params);
**
**
** drv_params.version_req = MC68328DIGI_VERSION;
** drv_params.event_queue_on = 1;
** drv_params.deglitch_on = 0;
** drv_params.sample_ms = 10;
** drv_params.follow_thrs = 0;
** drv_params.mv_thrs = 2;
** drv_params.y_max = 159 + 66;
** drv_params.y_min = 0;
** drv_params.x_max = 159;
** drv_params.x_min = 0;
** drv_params.xy_swap = 0;
**
**
**
** mx1 = 508; ux1 = 0;
** my1 = 508; uy1 = 0;
** mx2 = 188; ux2 = 159;
** my2 = 188; uy2 = 159;
**
**
** drv_params.x_ratio_num = ux1 - ux2;
** drv_params.x_ratio_den = mx1 - mx2;
** drv_params.x_offset =
** ux1 - mx1 * drv_params.x_ratio_num / drv_params.x_ratio_den;
**
** drv_params.y_ratio_num = uy1 - uy2;
** drv_params.y_ratio_den = my1 - my2;
** drv_params.y_offset =
** uy1 - my1 * drv_params.y_ratio_num / drv_params.y_ratio_den;
**
**
** printf("/nNew driver settings:/n");
** tsdrv_params_fprint(stdout, &drv_params);
**
** err = ioctl(ts_fd, TS_PARAMS_SET, &drv_params);
** if(err) {
** fprintf(stderr, "%s: ioctl TS_PARAMS_SET error: %s/n",
** argv[0], strerror(errno));
** close(ts_fd);
** return 0;
** }
**
** return ts_fd;
** }
**
**
**
**
**
** main(int argc, char *argv[])
** {
** int ts_fd = 0;
** struct ts_pen_info pen_info;
** int bytes_transfered = 0;
**
**
** ts_fd = tsdrv_init(argc, argv);
** if(ts_fd==0)
** exit(1);
**
**
** while(1) {
** char whats_up;
** int x, y;
** bytes_transfered = read(ts_fd, (void*)&pen_info, sizeof(pen_info));
** x = pen_info.x;
** y = pen_info.y;
**
** switch(pen_info.event) {
**
** case EV_PEN_UP:
** whats_up = 'U';
** break;
**
** case EV_PEN_DOWN:
** whats_up = 'D';
** break;
**
** case EV_PEN_MOVE:
** whats_up = 'M';
** break;
**
** default:
** whats_up = '?';
** }
**
** printf("%c(%i,%i) ", whats_up, x, y);
** printf("ev_no:%d ", pen_info.ev_no);
** printf("ev_usec:%ld ", pen_info.ev_time);
** printf("bytes_transfered:%d ", bytes_transfered);
** printf("/n");
** }
**
**
** close(ts_fd);
** exit(0);
** }
**
**
**
** <<< End of example ----------------------------------------------------------
*/
#endif /* _MC68328DIGI_H */
/* skyeye_ts_drv.c */
/*
*
* linux/drivers/char/skyeye_ts.c - Touch screen driver for touch screen simulated on skyeye.
*/
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/interrupt.h> /* We want interrupts */
#include <linux/miscdevice.h> /* for misc_register() and misc_deregister() */
#include <linux/fs.h> /* for struct 'file_operations' */
#include <linux/timer.h> /* for timeout interrupts */
#include <linux/param.h> /* for HZ. HZ = 100 and the timer step is 1/100 */
#include <linux/sched.h> /* for jiffies definition. jiffies is incremented
* once for each clock tick; thus it's incremented
* HZ times per secondes.*/
#include <linux/mm.h> /* for verify_area */
#include <linux/slab.h> /* for kmalloc */
#include <linux/init.h>
#include <asm/irq.h> /* For IRQ_MACHSPEC */
#include <linux/version.h>
/*----------------------------------------------------------------------------*/
//#include "mc68328digi.h" //struct ts_pen_info was defined in this head file
#include "skyeye_ts_drv.h"
//#include "ep7312_sys.h"
//#include "clps7110.h"
#define IRQ_FLG_STD (0x8000) /* internally used */
/*----------------------------------------------------------------------------*/
/* Available info from pen position and status */
//struct ts_pen_info {
//int x,y; /* pen position */
//int dx,dy; /* delta move from last position */
//int event; /* event from pen (DOWN,UP,CLICK,MOVE) */
//int state; /* state of pen (DOWN,UP,ERROR) */
//int ev_no; /* no of the event */
//unsigned long ev_time; /* time of the event (ms) since ts_open */
//};
static const char* __file__ = __FILE__;
/*----------------------------------------------------------------------------*//*
* Kernel compatibility.
* Kernel > 2.2.3, include/linux/version.h contain a macro for KERNEL_VERSION
*/
#include <linux/version.h>
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#endif
/*
* Conditional compilation. LINUX_VERSION_CODE is the code of this version
* (as per KERNEL_VERSION)
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
#include <asm/uaccess.h> /* for put_user */
#include <linux/poll.h> /* for polling fnct */
#endif
/*
* Length of the data structure
*/
#define DATA_LENGTH sizeof(struct ts_pen_info)
/*
* Size of the buffer for the event queue
*/
#define TS_BUF_SIZE 32*DATA_LENGTH
/*
* Minor number for the touch screen device. Major is 10 because of the misc
* type of the driver.
*/
//#define MC68328DIGI_MINOR 9
#define SKYEYE_TS_MINOR 9
#define SKYEYE_TS_MAJOR 10
int g_bChecked = 0; /* flag that is the first event */
int g_bNeedChgUp2Down = 0; /* flag that is need to exchange up and down event */
#define CHKEVT(event) (g_bNeedChgUp2Down ? (event==EV_PEN_DOWN ? EV_PEN_UP /
: (event==EV_PEN_UP ? EV_PEN_DOWN : EV_PEN_MOVE)) : event)
/*
* ADS7843 fields (BURR-BROWN Touch Screen Controller).
*/
#define ADS7843_START_BIT (1<<7)
#define ADS7843_A2 (1<<6)
#define ADS7843_A1 (1<<5)
#define ADS7843_A0 (1<<4)
#define ADS7843_MODE (1<<3) /* HIGH = 8, LOW = 12 bits conversion */
#define ADS7843_SER_DFR (1<<2) /* LOW = differential mode */
#define ADS7843_PD1 (1<<1) /* PD1,PD0 = 11 PENIRQ disable */
#define ADS7843_PD0 (1<<0) /* PD1,PD0 = 00 PENIRQ enable */
/*
* Conversion status.
*/
#define CONV_ERROR -1 /* error during conversion flow */
#define CONV_END 0 /* conversion ended (= pen is up) */
#define CONV_LOOP 1 /* conversion continue (= pen is down) */
/*
* Useful masks.
*/
#define PEN_IRQ_NUM SMDK2410_TS_IRQ
//#define PEN_IRQ_NUM IRQ6_IRQ_NUM
//#define PENIRQ_DATA PDDATA
//#define PENIRQ_PUEN PDPUEN
//#define PENIRQ_DIR PDDIR
//#define PENIRQ_SEL PDSEL
//#define ICR_PENPOL ICR_POL6
//#define IMR_MPEN IMR_MIRQ6
/*
* Touch screen driver states.
*/
#define TS_DRV_ERROR -1
#define TS_DRV_IDLE 0
#define TS_DRV_WAIT 1
#define TS_DRV_ASKX 2
#define TS_DRV_ASKY 3
#define TS_DRV_READX 4
#define TS_DRV_READY 5
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
//#define ENABLE_PEN_IRQ { INTSR &= ~EINT2; }
//#define DISABLE_PEN_IRQ { INTSR |= EINT2; }
//#define ENABLE_PEN_IRQ { INTSR &= ~EINT2; }
//#define DISABLE_PEN_IRQ { INTSR |= EINT2; }
#define ENABLE_PEN_IRQ
#define DISABLE_PEN_IRQ
#include <asm/io.h>
#include <mach/smdk2410.h>
#ifndef MOD_DEC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#ifndef MOD_INC_USE_COUNT
#define MOD_INC_USE_COUNT
#endif
static inline int verify_area(int type, const void __user *
addr,
unsigned long size)
{
return access_ok(type,addr,size) ? 0 : -EFAULT;
}
/*----------------------------------------------------------------------------*/
/* predefinitions ------------------------------------------------------------*/
static irqreturn_t handle_pen_irq(int irq, void *dev_id);
/*----------------------------------------------------------------------------*/
/* structure -----------------------------------------------------------------*/
struct ts_pen_position { int x,y; };
struct ts_queue {
unsigned long head;
unsigned long tail;
wait_queue_head_t proc_list;
struct fasync_struct *fasync;
unsigned char buf[TS_BUF_SIZE];
};
struct TS_RET {
unsigned short pressure;
unsigned short x;
unsigned short y;
unsigned short pad;
};
/*----------------------------------------------------------------------------*/
/* Variables -----------------------------------------------------------------*/
/*
* driver state variable.
*/
static int ts_drv_state;
/*
* first tick initiated at ts_open.
*/
//static struct timeval first_tick;
/*
* pen state.
*/
static int new_pen_state;
/*
* event counter.
*/
static int ev_counter;
/*
* counter to differentiate a click from a move.
*/
static int state_counter;
//static struct timer_list ts_wake_time;
/*
* drv parameters.
*/
static struct ts_drv_params current_params;
//static int sample_ticks;
/*
* pen info variables.
*/
static struct ts_pen_info ts_pen;
static struct ts_pen_info ts_pen_prev;
//static struct ts_pen_position current_pos;
static struct ts_pen_info current_pos;
//static struct ts_pen_info *buff;
/*
* driver management.
*/
static struct ts_queue *queue;
static int device_open = 0; /* number of open device to prevent concurrent
* access to the same device
*/
/*----------------------------------------------------------------------------*/
/* Init & release functions --------------------------------------------------*/
static void init_ts_state(void) {
//DISABLE_SPIM_IRQ; /* Disable SPIM interrupt */
ts_drv_state = TS_DRV_IDLE;
state_counter = 0;
ENABLE_PEN_IRQ; /* Enable interrupt IRQ5 */
}
static void init_ts_pen_values(void) {
}
/*
* Set default values for the params of the driver.
*/
static void init_ts_settings(void) {
}
static void init_ts_hardware(void) {
}
static void init_ts_drv(void) {
}
static void release_ts_drv(void) {
}
/*----------------------------------------------------------------------------*/
/* xcopilot compatibility hacks ----------------------------------------------*/
#ifdef CONFIG_XCOPILOT_BUGS
/* xcopilot has the following bugs:
*
* - Disabling the penirq has no effect; we keep on getting irqs even when
* penirq is disabled; this is not too annoying: we just trash pen irq events
* that come when disabled.
*
* - SPIM interrupt is not simulated; this is not too annoying: we just read
* SPI data immediately and bypass a couple of states related to SPI irq.
*
* - We do not get mouse drag events; this is a known xcopilot bug.
* This is annoying: we miss all moves ! You should patch and recompile
* your xcopilot.
*
* This has been reported as Debian bug #64367, and there is a patch there:
* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=64367&repeatmerged=yes
* which is:
* +-----------------------------------------------------------------------+
* | --- display.c Tue Aug 25 14:56:02 1998
* | +++ display2.c Fri May 19 16:07:52 2000
* | @@ -439,7 +439,7 @@
* | static void HandleDigitizer(Widget w, XtPointer client_data, XEvent/
* | *event, Boolean *continue_to_dispatch)
* | {
* | - Time start;
* | + static Time start;
* |
* | *continue_to_dispatch = True;
* +-----------------------------------------------------------------------+
* In short, add 'static' to the declaration of 'start' in HandleDigitizer()
* in display.c
*
* With this patch, all works perfectly !
*
* - The pen state can be read only in IPR, not in port D; again, we're doing
* the workaround.
*
* With all these workarounds in this file, and with the patch on xcopilot,
* things go perfectly smoothly.
*
*/
/*
* Ugly stuff to read the mouse position on xcopilot
*
* We get the position of the last mouse up/down only, we get no moves !!! :-(
*/
static void xcopilot_read_now(void) {
PFDATA &= ~0xf; PFDATA |= 6;
SPIMCONT |= SPIMCONT_XCH | SPIMCONT_IRQEN;
current_pos.x = SPIMDATA;
rescale_xpos(¤t_pos.x);
PFDATA &= ~0xf; PFDATA |= 9;
SPIMCONT |= SPIMCONT_XCH | SPIMCONT_IRQEN;
current_pos.y = SPIMDATA;
rescale_ypos(¤t_pos.y);
swap_xy(¤t_pos.x, ¤t_pos.y);
}
#endif
//****** by ywc 2004-04-09 ***************
static void skyeye_read_now(void){
long * TS_Buf_start_addr;
TS_Buf_start_addr=vSMDK2410_TS_IO+0x300;
current_pos.x=TS_Buf_start_addr[0];
current_pos.y=TS_Buf_start_addr[1];
current_pos.dx=0;
current_pos.dy=0;
current_pos.event=TS_Buf_start_addr[4];
current_pos.state=0;
current_pos.ev_no=TS_Buf_start_addr[6];//1--new data come,0--no new data--set by ts_read
current_pos.ev_time=0;
// printk("x=%d, y=%d, event=%d/n", current_pos.x, current_pos.y, current_pos.event);
// printk("&TS_Buf_start_addr[3]==%p/n",&TS_Buf_start_addr[3]);
// printk("ts driver: skyeye_read_now:");
// printk("current_pos.x=%d,current_pos.y=%d/n",current_pos.x,current_pos.y);
if(g_bChecked == 0) {
g_bChecked = 1;
g_bNeedChgUp2Down = (current_pos.event==EV_PEN_UP);
}
}
//****** by ywc 2004-04-09 ***************
/*
* Get one char from the queue buffer.
* AND the head with 'TS_BUF_SIZE -1' to have the loopback
*/
static unsigned char get_char_from_queue(void) {
unsigned int result;
result = queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (TS_BUF_SIZE - 1);
return result;
}
/*
* Write one event in the queue buffer.
* Test if there is place for an event = the head cannot be just one event
* length after the queue.
*/
static void put_in_queue(char *in, int len) {
unsigned long head = queue->head;
unsigned long maxhead = (queue->tail - len) & (TS_BUF_SIZE - 1);
int i;
if(head != maxhead) /* There is place for the event */
for(i=0;i<len;i++) {
queue->buf[head] = in[i];
head++;
head &= (TS_BUF_SIZE - 1);
}
//else printk("%0: Queue is full !!!!/n", __file__);
queue->head = head;
}
/*
* Test if queue is empty.
*/
static inline int queue_empty(void) {
return queue->head == queue->tail;
}
/*
* Test if the delta move of the pen is enough big to say that this is a really
* move and not due to noise.
*/
static int is_moving(void) {
int threshold;
int dx, dy;
threshold=((ts_pen_prev.event & EV_PEN_MOVE) > 0 ?
current_params.follow_thrs : current_params.mv_thrs);
dx = current_pos.x-ts_pen_prev.x;
dy = current_pos.y-ts_pen_prev.y;
if(dx < 0) dx = -dx; /* abs() */
if(dy < 0) dy = -dy;
return (dx > threshold ? 1 :
(dy > threshold ? 1 : 0));
}
static void copy_info(void) {
ts_pen_prev.x = ts_pen.x;
ts_pen_prev.y = ts_pen.y;
ts_pen_prev.dx = ts_pen.dx;
ts_pen_prev.dy = ts_pen.dy;
ts_pen_prev.event = ts_pen.event;
ts_pen_prev.state = ts_pen.state;
ts_pen_prev.ev_no = ts_pen.ev_no;
ts_pen_prev.ev_time = ts_pen.ev_time;
}
static void cause_event(int conv) {
switch(conv) {
case CONV_ERROR: /* error occure during conversion */
ts_pen.state &= 0; /* clear */
ts_pen.state |= ST_PEN_UP; /* recover a stable state for the drv. */
ts_pen.state |= ST_PEN_ERROR; /* tell that the state is due to an error */
ts_pen.event = EV_PEN_UP; /* event = pen go to up */
ts_pen.x = ts_pen_prev.x; /* get previous coord as current to by-pass */
ts_pen.y = ts_pen_prev.y; /* possible errors */
ts_pen.dx = 0;
ts_pen.dy = 0;
ts_pen.ev_no = ev_counter++; /* get no of event */
//ts_pen.ev_time = set_ev_time(); /* get time of event */
copy_info(); /* remember info */
if(current_params.event_queue_on)
put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */
/* tell user space progs that a new state occure */
new_pen_state = 1;
/* signal asynchronous readers that data arrives */
if(queue->fasync)
kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list); /* tell user space progs */
break;
case CONV_LOOP: /* pen is down, conversion continue */
ts_pen.state &= 0; /* clear */
ts_pen.state &= ST_PEN_DOWN;
switch(state_counter) { /* It could be a move */
case 1: /* the pen just went down, it's a new state */
ts_pen.x = current_pos.x;
ts_pen.y = current_pos.y;
ts_pen.dx = 0;
ts_pen.dy = 0;
ts_pen.event = EV_PEN_DOWN; /* event = pen go to down */
ts_pen.ev_no = ev_counter++; /* get no of event */
//ts_pen.ev_time = set_ev_time(); /* get time of event */
copy_info(); /* remember info */
if(current_params.event_queue_on)
put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */
/* tell user space progs that a new state occure */
new_pen_state = 1;
/* signal asynchronous readers that data arrives */
if(queue->fasync)
kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list); /* tell user space progs */
break;
case 2: /* the pen is down for at least 2 loop of the state machine */
if(is_moving()) {
ts_pen.event = EV_PEN_MOVE;
ts_pen.x = current_pos.x;
ts_pen.y = current_pos.y;
ts_pen.dx = ts_pen.x - ts_pen_prev.x;
ts_pen.dy = ts_pen.y - ts_pen_prev.y;
ts_pen.ev_no = ev_counter++; /* get no of event */
// ts_pen.ev_time = set_ev_time(); /* get time of event */
copy_info(); /* remember info */
if(current_params.event_queue_on)
put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */
/*
* pen is moving, then it's anyway a good reason to tell it to
* user space progs
*/
new_pen_state = 1;
/* signal asynchronous readers that data arrives */
if(queue->fasync)
kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
else {
if(ts_pen_prev.event == EV_PEN_MOVE) /* if previous state was moving */
ts_pen.event = EV_PEN_MOVE; /* -> keep it! */
ts_pen.x = ts_pen_prev.x; /* No coord passing to */
ts_pen.y = ts_pen_prev.y; /* avoid Parkinson effects */
ts_pen.dx = 0;
ts_pen.dy = 0; /* no wake-up interruptible because nothing new */
copy_info(); /* remember info */
}
break;
}
break;
case CONV_END: /* pen is up, conversion ends */
ts_pen.state &= 0; /* clear */
ts_pen.state |= ST_PEN_UP;
ts_pen.event = EV_PEN_UP;
ts_pen.x = current_pos.x;
ts_pen.y = current_pos.y;
ts_pen.dx = ts_pen.x - ts_pen_prev.x;
ts_pen.dy = ts_pen.y - ts_pen_prev.y;
// ts_pen.ev_time = set_ev_time(); /* get time of event */
ts_pen.ev_no = ev_counter++; /* get no of event */
copy_info(); /* remember info */
if(current_params.event_queue_on)
put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */
/* tell user space progs that a new state occure */
new_pen_state = 1;
/* signal asynchronous readers that data arrives */
if(queue->fasync)
kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
break;
}
}
/*----------------------------------------------------------------------------*/
/* Interrupt functions -------------------------------------------------------*/
/*
* pen irq.
*/
static irqreturn_t handle_pen_irq(int irq, void *dev_id) {
unsigned long flags;
//int bypass_initial_timer = 0;
/* if unwanted interrupts come, trash them */
if(!device_open)
return IRQ_NONE;
//PENIRQ_DATA &= ~PEN_MASK;
/* - Disabling the penirq has no effect; we keep on getting irqs even when
* penirq is disabled; this is not too annoying: we just trash pen irq events
* that come when disabled.
*/
// printk("enter the pen irq ,INTSR=%x",INTSR);
// if(!(INTSR&EINT2)) {
// return;
// }
//save_flags(flags); /* disable interrupts */
local_save_flags(flags); /* disable interrupts */
//cli();
local_irq_disable();
skyeye_read_now(); //ywc 2004-04-11
switch(ts_drv_state) {
case TS_DRV_IDLE:
// DISABLE_PEN_IRQ;
// ts_drv_state++; /* update driver state */
// if(current_params.deglitch_on)
// set_timer_irq(&ts_wake_time,sample_ticks);
// else
// bypass_initial_timer = 1;
break;
default: /* Error */
/* PENIRQ is enable then just init the driver
* Its not necessary to pull down the busy signal
*/
// init_ts_state();
break;
}
DISABLE_PEN_IRQ;
//restore_flags(flags); /* Enable interrupts */
local_irq_restore(flags); /* Enable interrupts */
return IRQ_HANDLED;
}
/*----------------------------------------------------------------------------*/
/* file_operations functions -------------------------------------------------*/
/*
* Called whenever a process attempts to read the device it has already open.
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
static ssize_t ts_read (struct file *file,
char *buff0, /* the buffer to fill with data */
size_t len, /* the length of the buffer. */
loff_t *offset) { /* Our offset in the file */
#else
static int ts_read(struct inode *inode, struct file *file,
char *buff0, /* the buffer to fill with data */
int len) { /* the length of the buffer. */
/* NO WRITE beyond that !!! */
#endif
//char *p_buffer;
//char c;
//int i;
int err;
//int havedata=0;
int ret=0;
// printk("!!!enter ts_read/n");
/*
while(!current_pos.state) { //no new data come
if(file->f_flags & O_NONBLOCK)
return -EAGAIN;
interruptible_sleep_on(&queue->proc_list);
#if (LINUX_VERSION_CODE >= 0x020100)
if(signal_pending(current))
#else
if(current->signal & ~current->blocked) // a signal arrived
#endif
return -ERESTARTSYS; //tell the fs layer to handle it
// otherwise loop
}
*/
/* Force length to the one available */
//len = DATA_LENGTH;
if(len < sizeof(struct TS_RET)) {
printk("ts_read: buffer too small!/n");
return ret;
}
/* verify that the user space address to write is valid */
err = verify_area(VERIFY_WRITE,buff0,len);
if (err) {
printk("verify_area error ,err=%d",err);
return err;
}
/*
for(i=0;i<len;i++){
buff[i]=*((char *)¤t_pos+i);
}
*/
//another copy way???
// struct ts_pen_info * buff;
if(current_pos.ev_no==1){
struct TS_RET *buff=(struct TS_RET *)buff0;
buff->x = current_pos.x;
buff->y = current_pos.y;
buff->pressure = CHKEVT(current_pos.event);
buff->pad = 0;
//buff->dx = current_pos.dx;
//buff->dy = current_pos.dy;
//buff->event = current_pos.event;
//buff->state = current_pos.state;
//buff->ev_no = current_pos.ev_no;
//buff->ev_time = current_pos.ev_time;
// printk("current_pos.x=%d,buff->x=%d/n",current_pos.x,buff->x);
// printk("current_pos.y=%d,buff->y=%d/n",current_pos.y,buff->y);
//havedata=1;
ret=sizeof(struct TS_RET);
}
current_pos.ev_no=0;// ywc 2004-04-12 data have been read ,set it to 0
// printk("!!!leave ts_read/n");
//return havedata;
return ret;
}
/*
* Called whenever a process attempts to open the device file.
*/
static int ts_open(struct inode *inode, struct file *file) {
int err;
/* To talk to only one device at a time */
//printk("!!!enter ts_open/n");
if(device_open) return -EBUSY;
/* IRQ registration have to be done before the hardware is instructed to
* generate interruptions.
*/
/* IRQ for pen */
err = request_irq(PEN_IRQ_NUM, handle_pen_irq,
IRQ_FLG_STD,"touch_screen",NULL);
if(err) {
printk("%s: Error. Cannot attach IRQ %d to touch screen device/n",
__file__, PEN_IRQ_NUM);
return err;
}
//printk("%s: IRQ %d attached to touch screen/n",
// __file__, PEN_IRQ_NUM);
init_ts_drv();
//printk("skyeye touch screen driver: init hardware done../n/n");
/* Init the queue */
queue = (struct ts_queue *) kmalloc(sizeof(*queue),GFP_KERNEL);
memset(queue,0,sizeof(*queue));
queue->head = queue->tail = 0;
init_waitqueue_head(&queue->proc_list);
/* Increment the usage count (number of opened references to the module)
* to be sure the module couldn't be removed while the file is open.
*/
MOD_INC_USE_COUNT;
/* And my own counter too */
device_open++;
//ts_read(0,0,0,0);
//file->f_op->read(1,1,1,1);
return 0; /* open succeed */
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
static int ts_fasync(int inode, struct file *file, int mode) {
#else
static int ts_fasync(struct inode *inode, struct file *file, int mode) {
#endif
int retval;
retval = fasync_helper(inode,file,mode,&queue->fasync);
if(retval < 0)
return retval;
return 0;
}
/*
* Called whenever a process attempts to close the device file.
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
static int ts_release(struct inode *inode, struct file *file) {
#else
static void ts_release(struct inode *inode, struct file *file) {
#endif
/* Remove this file from the asynchronously notified file's */
ts_fasync((int)inode,file,0);
/* Release hardware */
release_ts_drv();
/* Free the allocated memory for the queue */
kfree(queue);
/* IRQ have to be freed after the hardware is instructed not to interrupt
* the processor any more.
*/
//free_irq(SPI_IRQ_NUM,NULL);
free_irq(PEN_IRQ_NUM,NULL);
/* Decrement the usage count, otherwise once the file is open we'll never
* get rid of the module.
*/
MOD_DEC_USE_COUNT;
/* And my own counter too */
device_open--;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
return 0;
#endif
}
static struct file_operations ts_fops = {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
owner: THIS_MODULE,
read: ts_read,
//poll: ts_poll,
//ioctl: ts_ioctl,
open: ts_open,
release: ts_release,
fasync: ts_fasync,
#else
NULL, /* lseek */
ts_read, /* read */
NULL, /* write */
NULL, /* readdir */
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
ts_poll, /* poll */
# else
ts_select, /* select */
# endif
ts_ioctl, /* ioctl */
NULL, /* mmap */
ts_open, /* open */
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
NULL, /* flush */
# endif
ts_release, /* release (close) */
NULL, /* fsync */
ts_fasync /* async notification */
#endif
};
/*
* miscdevice structure for misc driver registration.
*/
static struct miscdevice mc68328_digi = {
// MC68328DIGI_MINOR,"mc68328 digitizer",&ts_fops
SKYEYE_TS_MINOR,"skyeye touch screen",&ts_fops
};
/*
* Initialize the driver.
*/
static int __init mc68328digi_init(void) {
int err;
//int ts;
printk("%s: SkyEye touch screen driver initialize/n", __file__);
/* Register the misc device driver */
err = misc_register(&mc68328_digi);
if(err<0)
printk("%s: Error registering the device/n", __file__);
else
printk("%s: Device register with name: %s and number: %d %d/n",
__file__, mc68328_digi.name, SKYEYE_TS_MAJOR, mc68328_digi.minor);
/* Init prameters settings at boot time */
init_ts_settings();
//******************* test by ywc 2004-3-27 *****************
/*
* open up the touch-panel device.
* Return the fd if successful, or negative if unsuccessful.
*/
/* opened by application on ts_driver!
ts = ts_open("/dev/ts", O_NONBLOCK | O_RDWR);
if (ts < 0) {
printk("Error opening touch panel/n");
return ts;
}
*/
//******************* test by ywc 2004-3-27 *****************
return err; /* A non zero value means that init_module failed */
}
/*
* Cleanup - undid whatever mc68328digi_init did.
*/
void mc68328digi_cleanup(void) {
/* Unregister device driver */
misc_deregister(&mc68328_digi);
}
module_init(mc68328digi_init);
module_exit(mc68328digi_cleanup);