📄 ucb1x00-ts.c~
字号:
/* * linux/drivers/misc/ucb1x00-ts.c * * Copyright (C) 2001 Russell King, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 21-Jan-2002 <jco@ict.es> : * * Added support for synchronous A/D mode. This mode is useful to * avoid noise induced in the touchpanel by the LCD, provided that * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin. * It is important to note that the signal connected to the ADCSYNC * pin should provide pulses even when the LCD is blanked, otherwise * a pen touch needed to unblank the LCD will never be read. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include <linux/completion.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/pm.h>#include <asm/dma.h>#include <asm/semaphore.h>#include "ucb1x00.h"/* * Define this if you want the UCB1x00 stuff to talk to the input layer */#ifdef CONFIG_INPUT#define USE_INPUT#else#undef USE_INPUT#endif#ifndef USE_INPUT#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/poll.h>/* * This structure is nonsense - millisecs is not very useful * since the field size is too small. Also, we SHOULD NOT * be exposing jiffies to user space directly. */struct ts_event { u16 pressure; u16 x; u16 y; u16 pad; struct timeval stamp;};#define NR_EVENTS 16#else#include <linux/input.h>#endifstruct ucb1x00_ts {#ifdef USE_INPUT struct input_dev idev;#endif struct ucb1x00 *ucb;#ifdef CONFIG_PM struct pm_dev *pmdev;#endif struct semaphore irq_wait; struct semaphore sem; struct completion init_exit; struct task_struct *rtask; int use_count; u16 x_res; u16 y_res;#ifndef USE_INPUT struct fasync_struct *fasync; wait_queue_head_t read_wait; u8 evt_head; u8 evt_tail; struct ts_event events[NR_EVENTS];#endif int restart:1; int adcsync:1;};static struct ucb1x00_ts ucbts;static int adcsync = UCB_NOSYNC;static int ucb1x00_ts_startup(struct ucb1x00_ts *ts);static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts);extern int pm_updatetimer(int);#ifndef USE_INPUT#define ucb1x00_ts_evt_pending(ts) ((volatile u8)(ts)->evt_head != (ts)->evt_tail)#define ucb1x00_ts_evt_get(ts) ((ts)->events + (ts)->evt_tail)#define ucb1x00_ts_evt_pull(ts) ((ts)->evt_tail = ((ts)->evt_tail + 1) & (NR_EVENTS - 1))#define ucb1x00_ts_evt_clear(ts) ((ts)->evt_head = (ts)->evt_tail = 0)static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y){ int next_head; next_head = (ts->evt_head + 1) & (NR_EVENTS - 1); if (next_head != ts->evt_tail) { ts->events[ts->evt_head].pressure = pressure; ts->events[ts->evt_head].x = x; ts->events[ts->evt_head].y = y; do_gettimeofday(&ts->events[ts->evt_head].stamp); ts->evt_head = next_head; if (ts->fasync) kill_fasync(&ts->fasync, SIGIO, POLL_IN); wake_up_interruptible(&ts->read_wait); }}static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts){ ucb1x00_ts_evt_add(ts, 0, 0, 0);}/* * User space driver interface. */static ssize_tucb1x00_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){ DECLARE_WAITQUEUE(wait, current); struct ucb1x00_ts *ts = filp->private_data; char *ptr = buffer; int err = 0; add_wait_queue(&ts->read_wait, &wait); while (count >= sizeof(struct ts_event)) { err = -ERESTARTSYS; if (signal_pending(current)) break; if (ucb1x00_ts_evt_pending(ts)) { struct ts_event *evt = ucb1x00_ts_evt_get(ts); err = copy_to_user(ptr, evt, sizeof(struct ts_event)); ucb1x00_ts_evt_pull(ts); if (err) break; ptr += sizeof(struct ts_event); count -= sizeof(struct ts_event); continue; } set_current_state(TASK_INTERRUPTIBLE); err = -EAGAIN; if (filp->f_flags & O_NONBLOCK) break; schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&ts->read_wait, &wait); return ptr == buffer ? err : ptr - buffer;}static unsigned int ucb1x00_ts_poll(struct file *filp, poll_table *wait){ struct ucb1x00_ts *ts = filp->private_data; int ret = 0; poll_wait(filp, &ts->read_wait, wait); if (ucb1x00_ts_evt_pending(ts)) ret = POLLIN | POLLRDNORM; return ret;}static int ucb1x00_ts_fasync(int fd, struct file *filp, int on){ struct ucb1x00_ts *ts = filp->private_data; return fasync_helper(fd, filp, on, &ts->fasync);}static int ucb1x00_ts_open(struct inode *inode, struct file *filp){ struct ucb1x00_ts *ts = &ucbts; int ret = 0; ret = ucb1x00_ts_startup(ts); if (ret == 0) filp->private_data = ts; return ret;}/* * Release touchscreen resources. Disable IRQs. */static int ucb1x00_ts_release(struct inode *inode, struct file *filp){ struct ucb1x00_ts *ts = filp->private_data; down(&ts->sem); ucb1x00_ts_fasync(-1, filp, 0); ucb1x00_ts_shutdown(ts); up(&ts->sem); return 0;}static struct file_operations ucb1x00_fops = { owner: THIS_MODULE, read: ucb1x00_ts_read, poll: ucb1x00_ts_poll, open: ucb1x00_ts_open, release: ucb1x00_ts_release, fasync: ucb1x00_ts_fasync,};/* * The official UCB1x00 touchscreen is a miscdevice: * 10 char Non-serial mice, misc features * 14 = /dev/touchscreen/ucb1x00 UCB 1x00 touchscreen */static struct miscdevice ucb1x00_ts_dev = { minor: 14, name: "touchscreen/ucb1x00", fops: &ucb1x00_fops,};static inline int ucb1x00_ts_register(struct ucb1x00_ts *ts){ init_waitqueue_head(&ts->read_wait); return misc_register(&ucb1x00_ts_dev);}static inline void ucb1x00_ts_deregister(struct ucb1x00_ts *ts){ misc_deregister(&ucb1x00_ts_dev);}#else#define ucb1x00_ts_evt_clear(ts) do { } while (0)static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y){ input_report_abs(&ts->idev, ABS_X, x); input_report_abs(&ts->idev, ABS_Y, y); input_report_abs(&ts->idev, ABS_PRESSURE, pressure);}static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts){ input_report_abs(&ts->idev, ABS_PRESSURE, 0);}static int ucb1x00_ts_open(struct input_dev *idev){ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; return ucb1x00_ts_startup(ts);}static void ucb1x00_ts_close(struct input_dev *idev){ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; down(&ts->sem); ucb1x00_ts_shutdown(ts); up(&ts->sem);}static inline int ucb1x00_ts_register(struct ucb1x00_ts *ts){ ts->idev.name = "Touchscreen panel"; ts->idev.idproduct = ts->ucb->id; ts->idev.open = ucb1x00_ts_open; ts->idev.close = ucb1x00_ts_close; __set_bit(EV_ABS, ts->idev.evbit); __set_bit(ABS_X, ts->idev.absbit); __set_bit(ABS_Y, ts->idev.absbit); __set_bit(ABS_PRESSURE, ts->idev.absbit); input_register_device(&ts->idev); return 0;}static inline void ucb1x00_ts_deregister(struct ucb1x00_ts *ts){ input_unregister_device(&ts->idev);}#endif/* * Switch to interrupt mode. */static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts){ if (ts->ucb->id == UCB_ID_1400_BUGGY) ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | UCB_TS_CR_MODE_INT); else ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | UCB_TS_CR_MODE_INT);}/* * Switch to pressure mode, and read pressure. We don't need to wait * here, since both plates are being driven. */static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts){ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);}/* * Switch to X position mode and measure Y plate. We switch the plate * configuration in pressure mode, then switch to position mode. This * gives a faster response time. Even so, we need to wait about 55us * for things to stabilise. */static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts){ int a,b,c;//bruce unsigned int d; int n=10000; ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); udelay(55); //bruce a=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); udelay(30); b=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); udelay(30); c=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //d=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //printk(KERN_EMERG "a:%d\n",a); //printk(KERN_EMERG "b:%d\n",b); //printk(KERN_EMERG "c:%d\n",c); //printk(KERN_EMERG "d:%d\n",d); //while(((b-a)>2)||((b-a)<-2)){ //a=(a+b)/2; //printk(KERN_EMERG "a:%d\n",a); //b=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //printk(KERN_EMERG "b:%d\n",b); //} //c=(a+b)/2; //while(((b-a)>1)||((b-a)<-1)){ //a=b; //b=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //printk(KERN_EMERG "b:%d\n",b); //} //c=b; while(((b-a)>4)||((b-a)<-4)||((c-a)>4)||((c-a)<-4)){ if(n>0){ n--; a=b;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -