diff -urN linux-2.4.0-test6-rmk5-np1/drivers/char/Config.in linux-2.4.0-test6-rmk5-np1-ts/drivers/char/Config.in --- linux-2.4.0-test6-rmk5-np1/drivers/char/Config.in Thu Aug 24 10:35:15 2000 +++ linux-2.4.0-test6-rmk5-np1-ts/drivers/char/Config.in Thu Aug 24 10:46:12 2000 @@ -15,6 +15,7 @@ fi tristate 'UCB1200 touchscreen support' CONFIG_TOUCHSCREEN_UCB1200 tristate 'Bitsy touchscreen support' CONFIG_TOUCHSCREEN_BITSY + tristate 'SA-1100 touchscreen support (Generic)' CONFIG_TOUCHSCREEN_SA1100 fi tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then diff -urN linux-2.4.0-test6-rmk5-np1/drivers/char/Makefile linux-2.4.0-test6-rmk5-np1-ts/drivers/char/Makefile --- linux-2.4.0-test6-rmk5-np1/drivers/char/Makefile Thu Aug 24 10:35:15 2000 +++ linux-2.4.0-test6-rmk5-np1-ts/drivers/char/Makefile Thu Aug 24 10:46:49 2000 @@ -105,6 +105,7 @@ obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o obj-$(CONFIG_TOUCHSCREEN_UCB1200) += ucb1200_ts.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3650_ts.o +obj-$(CONFIG_TOUCHSCREEN_SA1100) += sa1100ts_generic.o ifndef CONFIG_SUN_KEYBOARD obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) diff -urN linux-2.4.0-test6-rmk5-np1/drivers/char/sa1100ts_generic.c linux-2.4.0-test6-rmk5-np1-ts/drivers/char/sa1100ts_generic.c --- linux-2.4.0-test6-rmk5-np1/drivers/char/sa1100ts_generic.c Thu Jan 1 08:00:00 1970 +++ linux-2.4.0-test6-rmk5-np1-ts/drivers/char/sa1100ts_generic.c Thu Aug 24 10:54:25 2000 @@ -0,0 +1,991 @@ +/* + * Touch screen driver for Tifon + * uses the sa1100 and ucb1300 + * + * Copyright 1999 Peter Danielsson + * (codec routines shamelessy stolen from the audio driver) + * + * Modified By Allen and Peter (allen_cheng@xlinux.com & peter@xlinux.com) + * Add ioctl function for it. + * Add pen-up function + * + * Modified IRQ setting and for low-level irq handing.(chester@xlinux.com) + * Using GPIO_UCB1300_IRQ instead of irq 11 directly + * Change /dev/touchscreen to /dev/ts,and CHANGE the major + * number from 60 to 63. + * + * + * Todo : + * Add proc function + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +#include +#include +#endif + +#ifdef CONFIG_POWERMGR +#include +#endif + +#include +#include + +#include +#include + +#include + +struct touchinfo{ + mcp_reg *reg; /* physical address to mcp register */ + int mcp; + int id; /* codec id */ + int count; /* usage count */ + int state; /* current state of driver */ + struct timer_list timer; /* timer used in delays */ + wait_queue_head_t (proc_list); + struct calbration cal; + struct ts_data buf[BUFSIZE]; + struct fasync_struct *fasync; + int head; + int tail; +}; + +struct ts_data cur_data; +struct touchinfo ts; +unsigned int irq_count; + +// Allen Add +static mcp_state mcp_global; +int xx_min,yy_min,xx_pd,yy_pd; +int first=0; +// Allen + +void setADC(int); +static void ts_interrupt( int, void *, struct pt_regs *); +static inline void mcp_mcsr_wait_read(mcp_reg *); +static inline void mcp_mcsr_wait_write(mcp_reg *); +static int codec_read(mcp_reg *, int); +static void codec_write(mcp_reg *, int, int); +static int readADC(void); +static int pen_up(void); +void new_data(void); +struct ts_data get_data(void); +void store_p(int); +void store_x(int); +void store_y(int); +void wait_for_action(void); +void start_chain(void); +static void handle_timer(unsigned long); +void start_timer(void); + +// Allen Add +void print_par(void); +void ts_clear(void); +mcp_common_id MCP_common_register(void); +int MCP_common_enable(mcp_common_id); +int MCP_common_disable(mcp_common_id); +int MCP_common_unregister(mcp_common_id); + +static unsigned long in_timehandle=0; +static unsigned long in_count=0; + +/* mcp/codec operations */ +static inline void mcp_mcsr_wait_read(mcp_reg *mcp) +{ + /* wait for outstanding read to complete */ + while ((mcp->mcsr & MCSR_M_CRC) == 0) { /* spin */ } +} + +static inline void mcp_mcsr_wait_write(mcp_reg *mcp) +{ + /* wait for outstanding write to complete */ + while ((mcp->mcsr & MCSR_M_CWC) == 0) { /* spin */ } +} + +static int codec_read(mcp_reg *mcp, int addr) +{ + ulong flags; + int data; + + /* critical section */ + save_flags_cli(flags); + { + mcp_mcsr_wait_write(mcp); + mcp->mcdr2 = ((addr & 0xf) << MCDR2_V_RN); + mcp_mcsr_wait_read(mcp); + data = mcp->mcdr2 & 0xffff; + } + restore_flags(flags); + + return(data); +} + +static void codec_write(mcp_reg *mcp, int addr, int data) +{ + ulong flags; + + /* critical section */ + save_flags_cli(flags); + { + mcp_mcsr_wait_write(mcp); + mcp->mcdr2 = ((addr & 0xf) << MCDR2_V_RN) | MCDR2_M_nRW | (data & 0xffff); + } + restore_flags(flags); +} + +static int readADC( void ) +{ + int ret; + /* we have to check if conversion is ready */ + while(!((ret=codec_read(ts.reg, CODEC_ADC_DATA)) & ADC_DAT_VAL)); + return GET_DATA(ret); +} + + +static int pen_up( void ) +{ + int i=0; + + + codec_write(ts.reg, CODEC_ADC_CTL, 0 ); + codec_write(ts.reg, CODEC_TOUCH_CTL, (TSPX_POW | TSMX_POW | TSPY_GND | TSMY_GND )); + + i = codec_read(ts.reg, CODEC_TOUCH_CTL ) & (1 << 12); + i |= codec_read(ts.reg, CODEC_TOUCH_CTL ) & (1 << 13); + + return(i); +} + +/* data processing routines */ + +void new_data( void ) +{ + + in_count++; + + if(in_count < ABANDON) + return; + +#define PPOW 0x100 + + if (cur_data.p_raw < PPOW) + { + return; + } + + if (ts.head != ts.tail) + { + int last = ts.head--; + if (last < 0 ) + last = BUFSIZE-1; + +#define PLIMIT 50 +#define XLIMIT 50 +#define YLIMIT 50 + + if (abs(cur_data.p - ts.buf[last].p) < PLIMIT && abs(cur_data.y - ts.buf[last].y) < YLIMIT && + abs(cur_data.x - ts.buf[last].x) < XLIMIT && abs(jiffies-ts.buf[last].time) < MINTAP) + { + return; + } + } + cur_data.time = jiffies; + ts.buf[ts.head]=cur_data; + ts.head++; + if (ts.head == BUFSIZE) + ts.head = 0; + if (ts.head == ts.tail) + { + ts.tail++; + if( ts.tail == BUFSIZE ) + ts.tail = 0; + } + if (ts.fasync) + kill_fasync( ts.fasync, SIGIO, POLL_IN ); + + wake_up_interruptible( &ts.proc_list ); + +} + +struct ts_data get_data(void) +{ + int last; + + last = ts.tail; + + ts.tail++; + + if (ts.tail == BUFSIZE) + ts.tail=0; + + return ts.buf[last]; +} + + +void store_p(int p) +{ + cur_data.p_raw = p; + cur_data.p=p; +/* + if (p > ts.cal.p_threshold) + cur_data.p = (p*ts.cal.p_scale)/1024 + ts.cal.p_offset; +*/ +} + +void store_x(int x) +{ + cur_data.x_raw = x; + + +// Allen Add + ts.cal.x_min = xx_min; + ts.cal.y_min = yy_min; + ts.cal.x_pd = xx_pd; + ts.cal.y_pd = yy_pd; +// Allen + + + if (ts.cal.enable) + cur_data.x = (x - ts.cal.x_min)*SCALE/ts.cal.x_pd; + else + cur_data.x=x; + +// if (cur_data.x<0) +// print_par(); +} + +void store_y(int y) +{ + cur_data.y_raw = y; + +// Allen Add + ts.cal.x_min = xx_min; + ts.cal.y_min = yy_min; + ts.cal.x_pd = xx_pd; + ts.cal.y_pd = yy_pd; +// Allen + + if (ts.cal.enable) + cur_data.y = (y - ts.cal.y_min)*SCALE/ts.cal.y_pd; + else + cur_data.y=y; + +// if (cur_data.y<0) +// print_par(); +} + + +/* interrupt handling routines */ + +void wait_for_action( void ) +{ +/* set up for pen_down detection */ + in_count=0; + ts.state = 0; + codec_write(ts.reg, CODEC_TOUCH_CTL, TS_INTERRUPT ); + codec_write(ts.reg, 2, 0x0 ); + codec_write(ts.reg, 3, 0x3000 ); +} + +void start_chain(void) +{ +/* set up for pressure reading; */ + ts.state = P_DONE; + codec_write(ts.reg, CODEC_TOUCH_CTL, TS_PRESSURE ); + codec_write(ts.reg, 2, 1 << 11 ); + codec_write(ts.reg, 3, 0 ); + setADC(ADC_PRESSURE); +} + + +void setADC(int sel) +{ + codec_write(ts.reg, CODEC_ADC_CTL, ADC_ENA | ADC_SYNC_ENA | sel ); + codec_write(ts.reg, CODEC_ADC_CTL, ADC_ENA | ADC_SYNC_ENA | ADC_START | sel ); + codec_write(ts.reg, CODEC_IO_DATA, codec_read(ts.reg, CODEC_IO_DATA) | 0x200); + codec_write(ts.reg, CODEC_ADC_CTL, ADC_ENA | ADC_SYNC_ENA | sel ); + codec_write(ts.reg, CODEC_IO_DATA, codec_read(ts.reg, CODEC_IO_DATA) & ~0x200); +} + +static void handle_timer( unsigned long arg ) +{ + in_timehandle--; + + if (pen_up() ) + { + wait_for_action(); + ts.cal.penup = 1; + return; + } + else + { + start_chain(); + ts.cal.penup = 0; + } +} + + +void start_timer( void ) +{ + in_timehandle++; + + init_timer( &ts.timer ); + ts.timer.expires = jiffies + SAMPLE_INTERVAL; + ts.timer.function = handle_timer; + add_timer( &ts.timer ); +} + +static void ts_interrupt( int irq, void *dev_id, struct pt_regs *regs) +{ + + codec_write(ts.reg, 4,0); + codec_write(ts.reg, 4,0xffff); + + GEDR |= GPIO_UCB1300_IRQ; + + if (in_timehandle > 0) + return; + +// Allen add + if (ts.cal.enable==0) + first = 0; + + if ((first==0)&&(ts.cal.enable==1)) + { +// print_par(); + xx_min = ts.cal.x_min; + yy_min = ts.cal.y_min; + xx_pd = ts.cal.x_pd; + yy_pd = ts.cal.y_pd; + first = 1; + } +// Allen + + switch (ts.state) + { + case PRESSED: + start_chain(); + break; + case P_DONE: + /* set up for x reading; */ + store_p( readADC() ); + codec_write(ts.reg, CODEC_TOUCH_CTL, TS_XPOS ); + codec_write(ts.reg, 2, 1 << 11 ); + codec_write(ts.reg, 3, 0 ); + setADC(ADC_XPOS ); + ts.state++; + break; + case X_DONE: + /* set up for y reading */ + store_x( readADC() ); + codec_write(ts.reg, CODEC_TOUCH_CTL, TS_PRESSURE ); + codec_write(ts.reg, 2, 1 << 11 ); + codec_write(ts.reg, 3, 0 ); + setADC(ADC_PRESSURE); + ts.state++; + break; + + case P1_DONE: + codec_write(ts.reg, CODEC_TOUCH_CTL, TS_YPOS ); + codec_write(ts.reg, 2, 1 << 11 ); + codec_write(ts.reg, 3, 0 ); + setADC(ADC_YPOS ); + ts.state++; + break; + + case Y_DONE: + store_y( readADC() ); + /* set up for pen_up detection */ + codec_write(ts.reg, CODEC_TOUCH_CTL, TS_INTERRUPT ); + codec_write(ts.reg, 2, 0x3000 ); + codec_write(ts.reg, 3, 0 ); + ts.state++; + new_data(); + start_timer(); + break; + case RELEASED: + wait_for_action(); + break; + default: + panic("Unknown Touchscreen state\n"); + } + +} + + +/* interface functions */ + +static ssize_t ts_read(struct file *file, char *buf,size_t count, loff_t *offset) +{ +/* return position values from the buffer */ + + int i; + DECLARE_WAITQUEUE (wait, current); + + if (count % 6) + { + printk(KERN_INFO "EIO\n"); + return -EIO; + } + + if (NODATA) + { + if (file->f_flags & O_NONBLOCK) + { + printk(KERN_INFO "EAGAIN\n"); + return -EAGAIN; + } + + add_wait_queue( &ts.proc_list, &wait ); + + current->state = TASK_INTERRUPTIBLE; + while (NODATA && ! signal_pending(current)) + { + schedule(); + current->state = TASK_INTERRUPTIBLE; + } + current->state = TASK_RUNNING; + + remove_wait_queue(&ts.proc_list, &wait ); + } + + i=count; + + while (i > 5 && !NODATA) + { + struct data_packet p; + struct ts_data t = get_data(); + + p.x = t.x; + p.y = t.y; + p.p = t.p; + i -= 6; + + copy_to_user( buf, &p, 6 ); + + buf += 6; + } + + if (count-i ) + { + //file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count - i; + } + return 0; +} + +static unsigned int ts_poll( struct file *file, poll_table *wait) +{ +/* wait for data */ + poll_wait(file, &ts.proc_list, wait); + if (!NODATA) + return POLLIN | POLLRDNORM; + return 0; +} + +static ssize_t ts_write( struct file *file, char *buf,size_t count, loff_t *offset) +{ +/* return position values from the buffer */ + int i; + DECLARE_WAITQUEUE (wait, current); + + if (count % 6) + { + printk(KERN_INFO "EIO\n"); + return -EIO; + } + + i=count; + while ( i > 5 ) + { + struct data_packet p; + copy_from_user( &p, buf, 6 ); + + cur_data.x = p.x; + cur_data.y = p.y; + cur_data.p = p.p; + + i -= 6; + buf += 6; + + new_data(); + } + + if (count-i ) + { + return count - i; + } + return 0; +} + +static int ts_ioctl( struct inode *inode, struct file *file,unsigned int cmd, struct calbration * arg) +{ +/* serve ioctl requests for calibration */ + switch(cmd) + { + case TIOSET_CALI: + ts.cal.enable=1; + return copy_from_user(&ts.cal, arg, sizeof(struct calbration)); + + case TIOGET_CALI: + return copy_to_user((struct calbration *)arg, &ts.cal,sizeof(struct calbration)); + + case TIOEN_CALI: + ts.cal.enable=1; + return 0; + + case TIODIS_CALI: + ts.cal.enable=0; + return 0; + + case TIOGET_PENUP: + return copy_to_user((struct calbration *)arg, &ts.cal,sizeof(struct calbration)); + + case TIOGET_BUFCLR: + if (ts.tail==ts.head) + ts.cal.buf_clr = 1; + else + ts.cal.buf_clr = 0; + return copy_to_user((struct calbration *)arg, &ts.cal,sizeof(struct calbration)); + + case TIO_BUF_CLR: + ts_clear(); + return 0; + + default: + return -EINVAL; + } +} + +static int ts_fasync( int fd, struct file *file, int on ) +{ +/* handle asynchronous notification */ + int retval; + + retval = fasync_helper( fd, file, on, &ts.fasync ); + if (retval < 0 ) + return retval; + return 0; +} + +static int ts_open( struct inode *inode, struct file *file) +{ +/* initialize mcp and interrupts */ + if (ts.count == 0) + { + init_waitqueue_head (&ts.proc_list); + + MCP_common_enable(ts.mcp); + + GPDR &= ~GPIO_UCB1300_IRQ; + set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ,GPIO_RISING_EDGE); +//don't touch GRER/GEDR/GFER directly + + if (request_irq(IRQ_GPIO_UCB1300_IRQ, ts_interrupt, SA_SHIRQ,"ts", NULL)) + { + printk(KERN_INFO "error request irq\n"); + return -EBUSY; + } + codec_write(ts.reg, CODEC_IO_DIRECTION,codec_read(ts.reg,CODEC_IO_DIRECTION) | 0x200); + codec_write(ts.reg, 2, 0 ); + codec_write(ts.reg, 3, 0 ); + ts.head = ts.tail = 0; + wait_for_action(); + } + MOD_INC_USE_COUNT; + ts.count++; + +/* test keyboard */ + return 0; +} + +static int ts_close( struct inode *inode, struct file *file) +{ +/* close mcp and free interrupts */ + ts.count--; + if (ts.count == 0) + { +// Allen add + ts_clear(); + + codec_write(ts.reg, 2, 0x0 ); + codec_write(ts.reg, 3, 0x0 ); + codec_write(ts.reg, 4, 0x0 ); + codec_write(ts.reg, 4, 0xffff); + codec_write(ts.reg, 10, 0x0 ); + + GEDR |= GPIO_UCB1300_IRQ; +// Allen + + MCP_common_disable(ts.mcp); + free_irq(IRQ_GPIO_UCB1300_IRQ, NULL ); + } + ts_fasync(-1, file, 0); + MOD_DEC_USE_COUNT; + + return 0; +} + + +void ts_clear(void) +{ + int i; + + for (i=0; i < BUFSIZE; i++) + { + ts.buf[i].p=(int)NULL; + ts.buf[i].x=(int)NULL; + ts.buf[i].y=(int)NULL; + ts.buf[i].p_raw=(int)NULL; + ts.buf[i].x_raw=(int)NULL; + ts.buf[i].y_raw=(int)NULL; + ts.buf[i].time=(unsigned long)NULL; + } + + ts.tail=ts.head; + + return 0; +} + + +static int ts_flush( struct inode *inode, struct file *file) +{ + ts.tail=ts.head; + return 0; +} + +// Allen Add +void print_par(void) +{ + printk(" Kernel ==> ts.cal.enable = %d\n",ts.cal.enable); + printk(" Kernel ==> ts.cal.x_min = %d\n",ts.cal.x_min); + printk(" Kernel ==> ts.cal.y_min = %d\n",ts.cal.y_min); + printk(" Kernel ==> ts.cal.x_pd = %d\n",ts.cal.x_pd); + printk(" Kernel ==> ts.cal.y_pd = %d\n",ts.cal.y_pd); + printk(" Kernel ==> ts.cal.penup = %d\n",ts.cal.penup); + printk(" Kernel ==> ts.cal.buf_clr = %d\n",ts.cal.buf_clr); +} + + +mcp_common_id MCP_common_register(void) +{ + /* + * modifies: mcp_global + * effects: Register as user of SA1100 MCP. Returns a unique mcp id + * for use with future calls, or MCP_COMMON_ID_INVALID if + * unable to register. + */ + + mcp_state *m = &mcp_global; + mcp_common_id id; + ulong flags, i; + + /* search bitmask for available id */ + id = MCP_COMMON_ID_INVALID; + save_flags_cli(flags); + for (i = 0; i <= MCP_COMMON_ID_MAX; i++) + if ((m->id_mask & (1 << i)) == 0) + { + /* allocate id, clear enabled */ + m->id_mask |= (1 << i); + m->enabled_mask &= ~(1 << i); + id = (mcp_common_id) i; + break; + } + restore_flags(flags); + +/* +#ifdef MODULE + if (id != MCP_COMMON_ID_INVALID) + { + MOD_INC_USE_COUNT; + } +#endif +*/ + + return(id); +} + +int MCP_common_enable(mcp_common_id id) +{ + /* + * modifies: mcp_global + * effects: Turns on SA1100 MCP; no effect if MCP is already on. + * Redundant calls with the same id are safely ignored. + * Returns 0 iff successful, otherwise returns error code. + */ + + mcp_state *m = &mcp_global; + ulong flags; + + /* sanity checks */ + if ((id < 0) || (id > MCP_COMMON_ID_MAX)) + return(-EINVAL); + if ((m->id_mask & (1 << id)) == 0) + return(-EINVAL); + + save_flags_cli(flags); + if ((m->enabled_mask & (1 << id)) == 0) + { + /* turn on if necessary */ + if (m->enabled_mask == 0) + MCP_enable_prim(m); + m->enabled_mask |= (1 << id); + } + restore_flags(flags); + + /* update stats */ + m->enable_count++; + + /* successful */ + return(0); +} + +int MCP_common_disable(mcp_common_id id) +{ + /* + * modifies: mcp_global + * effects: Turns off SA1100 MCP; no effect if MCP is already off. + * Redundant calls with the same id are safely ignored. + * Returns 0 iff successful, otherwise returns error code. + * + */ + + mcp_state *m = &mcp_global; + ulong flags; + + /* sanity checks */ + if ((id < 0) || (id > MCP_COMMON_ID_MAX)) + return(-EINVAL); + if ((m->id_mask & (1 << id)) == 0) + return(-EINVAL); + + save_flags_cli(flags); + if (m->enabled_mask & (1 << id)) + { + /* turn off if necessary */ + m->enabled_mask &= ~(1 << id); + if (m->enabled_mask == 0) + MCP_disable_prim(m); + } + restore_flags(flags); + + /* update stats */ + m->disable_count++; + + /* successful */ + return(0); +} + +int MCP_common_unregister(mcp_common_id id) +{ + /* + * modifies: mcp_global + * effects: Deregisters id as user of SA1100 MCP. + * Returns 0 iff successful, otherwise returns error code. + * + */ + + mcp_state *m = &mcp_global; + ulong flags; + int retval; + + /* sanity check */ + if ((id < 0) || (id > MCP_COMMON_ID_MAX)) + return(-EINVAL); + + /* search bitmask for id */ + save_flags_cli(flags); + if (m->id_mask & (1 << id)) + { + /* deallocate id, forcibly disable */ + retval = 0; + m->id_mask &= ~(1 << id); + if (m->enabled_mask & (1 << id)) + (void) MCP_common_disable(id); + } + else + { + /* id not allocated */ + retval = -EINVAL; + } + restore_flags(flags); + +/* +#ifdef MODULE + if (retval == 0) + { + MOD_DEC_USE_COUNT; + } +#endif +*/ + + return(retval); +} + +static inline void MCP_enable_prim(mcp_state *m) +{ + /* turn on the MCP */ + int asd = CODEC_ASD_NUMERATOR / AUDIO_RATE_DEFAULT; + m->mcp->mccr = 0; + m->mcp->mccr = MCCR_M_ADM | MCCR_M_MCE | (40 << MCCR_V_TSD) | asd; + + /* update stats */ + m->prim_enable_count++; + + if (MCP_DEBUG_VERBOSE) + printk(MCP_MODULE_NAME ": mcp_enable_prim\n"); +} + +static inline void MCP_disable_prim(mcp_state *m) +{ + /* turn off the MCP */ + m->mcp->mccr = 0; + + /* update stats */ + m->prim_disable_count++; + + if (MCP_DEBUG_VERBOSE) + printk(MCP_MODULE_NAME ": mcp_disable_prim\n"); +} + +static void MCP_state_init(mcp_state *m) +{ + /* initialize mcp state */ + memset((void *) m, 0, sizeof(mcp_state)); + m->mcp = MCP_BASE_V; + m->id_mask = 0; + m->enabled_mask = 0; + + /* initialize stats */ + m->enable_count = 0; + m->disable_count = 0; + m->prim_enable_count = 0; + m->prim_disable_count = 0; + +#ifdef CONFIG_POWERMGR + /* initialize powermgr state */ + m->pm_id = POWERMGR_ID_INVALID; +#endif /* CONFIG_POWERMGR */ +} + +// Allen + + +// Allen Modify +/* The file_operations struct is changed from 2.3.99-p6 to 2.4.0. + That has to add descriptor at the head. Please carefully!!! */ +static struct file_operations ts_fops = { + read: ts_read, /* read */ + write: ts_write, /* write */ + poll: ts_poll, /* poll */ + ioctl: ts_ioctl, /* ioctl */ + open: ts_open, /* open */ + flush: ts_flush, /* flush */ + release: ts_close, /* close */ + fasync: ts_fasync /* fasync*/ +}; +// Allen + + +/* PhantomCat */ +/* For ZWIN. Writed by Allen and modified by Peter */ + +static int __init touch_init(void) +{ + int err; + + if (MCP_DEBUG_VERBOSE) + printk(MCP_MODULE_NAME ": initializing\n"); + + /* initialize global state */ + MCP_state_init(&mcp_global); + +#ifdef CONFIG_POWERMGR + mcp_global.pm_id = powermgr_register(&mcp_powermgr); + if (mcp_global.pm_id == POWERMGR_ID_INVALID) + if (MCP_DEBUG) + printk(MCP_MODULE_NAME ": init_module: powermgr_register failed\n"); +#endif /* CONFIG_POWERMGR */ + + /* log registration */ + printk(MCP_MODULE_NAME_VERBOSE " initalized\n"); + + memset(&ts, 0, sizeof(ts)); + memset(&ts.cal, 1, sizeof(struct calbration)); + ts.reg = (mcp_reg *)&Ser4MCCR0; // Ser4MCCR0 = 0x80060000 + + if ((err = register_chrdev(TS_MAJOR, TS_NAME, &ts_fops))) + { + /* TS_MAJOR = 63 ; TS_NAME = "ts" */ + printk("Unable to get major %d for device %s\n",TS_MAJOR, TS_NAME); + return err; + } + + + if ((ts.mcp = MCP_common_register()) == MCP_COMMON_ID_INVALID) + { + printk(KERN_INFO "%s could not get access to mcp\n", TS_NAME); + unregister_chrdev( TS_MAJOR, TS_NAME ); + return -1; + } + + BCR_set(BCR_CODEC_RST); // Reset the UCB1300 + + MCP_common_enable(ts.mcp); + ts.id = codec_read( ts.reg, 12 ); + MCP_common_disable(ts.mcp); + + + if (ts.id == 0) + { + printk(KERN_INFO "%s device id is zero - aborting\n", TS_NAME); + MCP_common_unregister( ts.mcp ); + unregister_chrdev( TS_MAJOR, TS_NAME ); + return -1; + } + + printk(KERN_INFO "Touchscreen driver SA1100-generic(UCB1200) initalized \n"); + + ts.cal.enable=0; + ts.cal.x_min=1; + ts.cal.x_max=1; + ts.cal.x_pd=1; + ts.cal.y_min=1; + ts.cal.y_max=1; + ts.cal.y_pd=1; + ts.cal.p_min=1; + ts.cal.p_max=1; + ts.cal.p_pd=1; + ts.cal.buf_clr=1; + ts.cal.penup=1; + + return 0; +} + + +static void __exit touch_exit( void ) +{ + BCR_clear(BCR_CODEC_RST); + unregister_chrdev(TS_MAJOR, TS_NAME); + MCP_common_unregister( ts.mcp ); +} + +module_init(touch_init); +module_exit(touch_exit); + diff -urN linux-2.4.0-test6-rmk5-np1/include/linux/sa1100ts_generic.h linux-2.4.0-test6-rmk5-np1-ts/include/linux/sa1100ts_generic.h --- linux-2.4.0-test6-rmk5-np1/include/linux/sa1100ts_generic.h Thu Jan 1 08:00:00 1970 +++ linux-2.4.0-test6-rmk5-np1-ts/include/linux/sa1100ts_generic.h Thu Aug 24 11:05:11 2000 @@ -0,0 +1,231 @@ +#ifndef _LINUX_TOUCH_H +#define _LINUX_TOUCH_H + +/* jiffies between samples */ +//#define SAMPLE_INTERVAL 10 +#define SAMPLE_INTERVAL 5 + +/* minimum delay to register as double-tap */ +#define MINTAP (3*SAMPLE_INTERVAL) + +//#define ABANDON 3 +#define ABANDON 2 + + +/* codec registers */ +#define CODEC_IO_DATA (0) +#define CODEC_IO_DIRECTION (1) +#define CODEC_RE_INT_ENABLE (2) +#define CODEC_FE_INT_ENABLE (3) +#define CODEC_INT_STATCLR (4) +#define CODEC_TELCOM_CTL_A (5) +#define CODEC_TELCOM_CTL_B (6) +#define CODEC_AUDIO_CTL_A (7) +#define CODEC_AUDIO_CTL_B (8) +#define CODEC_TOUCH_CTL (9) +#define CODEC_ADC_CTL (10) +#define CODEC_ADC_DATA (11) +#define CODEC_ID (12) +#define CODEC_MODE (13) + +#define TSMX_POW 0x1 +#define TSPX_POW 0x2 +#define TSMY_POW 0x4 +#define TSPY_POW 0x8 +#define TSMX_GND 0x10 +#define TSPX_GND 0x20 +#define TSMY_GND 0x40 +#define TSPY_GND 0x80 +#define TSC_MODE_INT 0x000 +#define TSC_MODE_PRES 0x100 +#define TSC_MODE_POS 0x200 +#define TSC_BIAS_ENA 0x800 +#define TSPX_LOW 0x1000 +#define TSMX_LOW 0x2000 + +/* Register CODEC_ADC_CTL */ +#define ADC_SYNC_ENA 0x1 +#define ADC_INPUT_TSPX 0x0 +#define ADC_INPUT_TSMX 0x4 +#define ADC_INPUT_TSPY 0x8 +#define ADC_INPUT_TSMY 0xc +#define ADC_INPUT_AD0 0x10 +#define ADC_INPUT_AD1 0x14 +#define ADC_INPUT_AD2 0x18 +#define ADC_INPUT_AD3 0x1c +#define EXT_REF_ENA 0x20 +#define ADC_START 0x80 +#define ADC_ENA 0x8000 + +#define PRESSED 0 +#define P_DONE 1 +#define X_DONE 2 +#define P1_DONE 3 +#define Y_DONE 4 +#define RELEASED 5 + +/* AUDIO_SET_RATE args [samples/sec] */ +#define AUDIO_RATE_MIN (3000) +#define AUDIO_RATE_MAX (41500) +#define AUDIO_RATE_DEFAULT (11025) + + + +/* Register 11 */ +#define ADC_DAT_VAL 0x8000 +#define GET_DATA(x) (((x)>>5)&0x3ff) + +#define ADC_ENA_TYPE (ADC_SYNC_ENA | ADC_ENA) + +#define TS_INTERRUPT (TSPX_POW | TSMX_POW | TSPY_GND | TSMY_GND | TSC_MODE_INT ) + +#define TS_PRESSURE (TSPX_POW | TSMX_POW | TSPY_GND | TSMY_GND | TSC_MODE_PRES | TSC_BIAS_ENA ) + +#define ADC_PRESSURE 0 + +#define TS_XPOS (TSPX_POW | TSMX_GND | TSC_MODE_POS | TSC_BIAS_ENA ) + +#define ADC_XPOS (ADC_INPUT_TSMY) + +#define TS_YPOS (TSPY_GND | TSMY_POW | TSC_MODE_POS | TSC_BIAS_ENA ) + +#define ADC_YPOS (ADC_INPUT_TSMX) + +/* Allen Add + ** Change MAJOR No. from 60 to 63 when upgrade kernel from 2.3.99-p6 to 2.4.0,and + TS_NAME change from "touchscreen" to "ts". */ +/* Allen */ +//#define TS_IRQ 11 +#define TS_MAJOR 63 +#define TS_NAME "ts" + +#define BUFSIZE 10 +#define SCALE 1024 + + +#define NODATA (ts.head == ts.tail) + +#define TIOGET_CALI _IOR('T', 0 , struct calbration) +#define TIOSET_CALI _IOW('T', 1 , struct calbration) +#define TIOEN_CALI _IOW('T', 2 , int) +#define TIODIS_CALI _IOW('T', 3 , int) +#define TIOGET_PENUP _IOR('T', 4 , struct calbration) +#define TIOGET_BUFCLR _IOR('T', 5 , struct calbration) +#define TIO_BUF_CLR _IOW('T', 6 , int) + +struct ts_data{ + int p; + int x; + int y; + int p_raw; + int x_raw; + int y_raw; + unsigned long time; +}; + +struct data_packet { + unsigned short p; /* pressure value */ + unsigned short x; + unsigned short y; +}; + +struct calbration { + /* PhantomCat, defined by allen */ + int enable; + int x_max; /* offset for x pos */ + int y_max; + int p_max; + int x_min; /* offset for x pos */ + int y_min; + int p_min; + int x_pd; /* offset for x pos */ + int y_pd; + int p_pd; + int penup; + int buf_clr; + /* PhantomCat */ +}; + + +// Allen Add +#define MCP_BASE_V ((mcp_reg *) &Ser4MCCR0) + +#define MCP_DEBUG (1) +#define MCP_DEBUG_VERBOSE (0) + +#define MCP_COMMON_ID_INVALID (-1) +#define MCP_COMMON_ID_MAX (31) + +#define MCCR_V_ASD 0 +#define MCCR_V_TSD 8 +#define MCCR_M_MCE 0x010000 +#define MCCR_M_ECS 0x020000 +#define MCCR_M_ADM 0x040000 +#define MCCR_M_TTM 0x080000 +#define MCCR_M_TRM 0x100000 +#define MCCR_M_ATE 0x200000 +#define MCCR_M_ARE 0x400000 +#define MCCR_M_LBM 0x800000 + +#define MCDR2_V_RN 17 +#define MCDR2_M_nRW 0x10000 + +#define MCSR_M_ATS 0x00000001 +#define MCSR_M_ARS 0x00000002 +#define MCSR_M_TTS 0x00000004 +#define MCSR_M_TRS 0x00000008 +#define MCSR_M_ATU 0x00000010 +#define MCSR_M_ARO 0x00000020 +#define MCSR_M_TTU 0x00000040 +#define MCSR_M_TRO 0x00000080 +#define MCSR_M_ANF 0x00000100 +#define MCSR_M_ANE 0x00000200 +#define MCSR_M_TNF 0x00000400 +#define MCSR_M_TNE 0x00000800 +#define MCSR_M_CWC 0x00001000 +#define MCSR_M_CRC 0x00002000 +#define MCSR_M_ACE 0x00004000 +#define MCSR_M_TCE 0x00008000 + + +/* names */ +#define MCP_MODULE_NAME "mcp-common" +#define MCP_MODULE_NAME_VERBOSE "MCP SA1100/UCB1200 module" +#define MCP_VERSION_STRING "$Revision: 2.0 $" + +/* codec */ +#define CODEC_ASD_NUMERATOR (375000) + +typedef int mcp_common_id; + +typedef struct { + volatile uint mccr; + volatile uint reserved0; + volatile uint mcdr0; + volatile uint mcdr1; + volatile uint mcdr2; + volatile uint reserved1; + volatile uint mcsr; +} mcp_reg; + +typedef struct { + /* memory-mapped mcp */ + mcp_reg *mcp; + + /* bitmasks */ + ulong id_mask; + ulong enabled_mask; + + /* statistics */ + ulong enable_count; + ulong disable_count; + ulong prim_enable_count; + ulong prim_disable_count; + +#ifdef CONFIG_POWERMGR + /* power management */ + powermgr_id pm_id; +#endif +} mcp_state; + +#endif /* _LINUX_TOUCH_H */