?? 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
/*
* 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 6
//#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; }
/*----------------------------------------------------------------------------*/
/* predefinitions ------------------------------------------------------------*/
static void handle_pen_irq(int irq, void *dev_id, struct pt_regs *regs);
/*----------------------------------------------------------------------------*/
/* 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];
};
/*----------------------------------------------------------------------------*/
/* 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=0xff00b000;
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("&TS_Buf_start_addr[2]==%p\n",&TS_Buf_start_addr[2]);
// 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\n",current_pos.x,current_pos.y);
}
//****** 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)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -