📄 ucb1x00-ts.c~
字号:
b=c; udelay(26); c=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); }else{ break; }//printk(KERN_EMERG "d:%d\n",d); } //printk(KERN_EMERG "n:%d\n",n); //while(((b-a)>5)||((b-a)<-5)||((c-a)>5)||((c-a)<-5)||((d-a)>5)||((d-a)<-5)){ //a=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //b=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //c=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //d=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); //} d=c; //printk(KERN_EMERG "x:%d\n",d); return d; //return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);}/* * Switch to Y position mode and measure X 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_ypos(struct ucb1x00_ts *ts){ //bruce int a,b,c; unsigned int d; int m=10000; ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); udelay(55); //bruce //return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); a=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); udelay(30); b=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); udelay(30); c=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); //d=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, 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_TSPX, 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_TSPX, 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(m>0){ m--; a=b; b=c; udelay(26); c=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); }else{ break; } //printk(KERN_EMERG "c:%d\n",c); } //printk(KERN_EMERG "m:%d\n",m); //while(((b-a)>5)||((b-a)<-5)||((c-a)>5)||((c-a)<-5)||((d-a)>5)||((d-a)<-5)){ //a=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); //b=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); //c=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); //d=ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); //} d=c; //printk(KERN_EMERG "y:%d\n",d); return d;}/* * Switch to X plate resistance mode. Set MX to ground, PX to * supply. Measure current. */static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts){ 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); return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);}/* * Switch to Y plate resistance mode. Set MY to ground, PY to * supply. Measure current. */static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts){ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);}/* * This is a RT kernel thread that handles the ADC accesses * (mainly so we can use semaphores in the UCB1200 core code * to serialise accesses to the ADC). The UCB1400 access * functions are expected to be able to sleep as well. */static int ucb1x00_thread(void *_ts){ struct ucb1x00_ts *ts = _ts; struct task_struct *tsk = current; int valid; ts->rtask = tsk; daemonize(); reparent_to_init(); strcpy(tsk->comm, "ktsd"); tsk->tty = NULL; /* * We could run as a real-time thread. However, thus far * this doesn't seem to be necessary. */// tsk->policy = SCHED_FIFO;// tsk->rt_priority = 1; /* only want to receive SIGKILL */ spin_lock_irq(&tsk->sigmask_lock); siginitsetinv(&tsk->blocked, sigmask(SIGKILL)); recalc_sigpending(tsk); spin_unlock_irq(&tsk->sigmask_lock); complete(&ts->init_exit); valid = 0; for (;;) { unsigned int x, y, p, val; ts->restart = 0; ucb1x00_adc_enable(ts->ucb); x = ucb1x00_ts_read_xpos(ts); y = ucb1x00_ts_read_ypos(ts); p = ucb1x00_ts_read_pressure(ts); /* * Switch back to interrupt mode. */ ucb1x00_ts_mode_int(ts); ucb1x00_adc_disable(ts->ucb); set_task_state(tsk, TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 100); if (signal_pending(tsk)) break; ucb1x00_enable(ts->ucb); val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) { ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); ucb1x00_disable(ts->ucb); /* * If we spat out a valid sample set last time, * spit out a "pen off" sample here. */ if (valid) { ucb1x00_ts_event_release(ts); valid = 0; } /* * Since ucb1x00_enable_irq() might sleep due * to the way the UCB1400 regs are accessed, we * can't use set_task_state() before that call, * and not changing state before enabling the * interrupt is racy. A semaphore solves all * those issues quite nicely. */ down_interruptible(&ts->irq_wait); } else { ucb1x00_disable(ts->ucb); /* * Filtering is policy. Policy belongs in user * space. We therefore leave it to user space * to do any filtering they please. */ if (!ts->restart) { ucb1x00_ts_evt_add(ts, p, x, y); valid = 1; } set_task_state(tsk, TASK_INTERRUPTIBLE); schedule_timeout(HZ / 100); } if (signal_pending(tsk)) break; } ts->rtask = NULL; ucb1x00_ts_evt_clear(ts); complete_and_exit(&ts->init_exit, 0);}/* * We only detect touch screen _touches_ with this interrupt * handler, and even then we just schedule our task. */static void ucb1x00_ts_irq(int idx, void *id){ struct ucb1x00_ts *ts = id; ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);#if defined( CONFIG_PM ) pm_updatetimer(0);#endif up(&ts->irq_wait);}static int ucb1x00_ts_startup(struct ucb1x00_ts *ts){ int ret = 0; if (down_interruptible(&ts->sem)) return -EINTR; if (ts->use_count++ != 0) goto out; if (ts->rtask) panic("ucb1x00: rtask running?"); sema_init(&ts->irq_wait, 0); ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); if (ret < 0) goto out; /* * If we do this at all, we should allow the user to * measure and read the X and Y resistance at any time. */ ucb1x00_adc_enable(ts->ucb); ts->x_res = ucb1x00_ts_read_xres(ts); ts->y_res = ucb1x00_ts_read_yres(ts); ucb1x00_adc_disable(ts->ucb); init_completion(&ts->init_exit); ret = kernel_thread(ucb1x00_thread, ts, 0); if (ret >= 0) { wait_for_completion(&ts->init_exit); ret = 0; } else { ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); } out: if (ret) ts->use_count--; up(&ts->sem); return ret;}/* * Release touchscreen resources. Disable IRQs. */static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts){ if (--ts->use_count == 0) { if (ts->rtask) { send_sig(SIGKILL, ts->rtask, 1); wait_for_completion(&ts->init_exit); } ucb1x00_enable(ts->ucb); ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); ucb1x00_disable(ts->ucb); }}#ifdef CONFIG_PMstatic int ucb1x00_ts_pm (struct pm_dev *dev, pm_request_t rqst, void *data){ struct ucb1x00_ts *ts = (struct ucb1x00_ts *) (dev->data); if (rqst == PM_RESUME && ts->rtask != NULL) { /* * Restart the TS thread to ensure the * TS interrupt mode is set up again * after sleep. */ ts->restart = 1; up(&ts->irq_wait); } return 0;}#endif/* * Initialisation. */static int __init ucb1x00_ts_init(void){ struct ucb1x00_ts *ts = &ucbts; ts->ucb = ucb1x00_get(); if (!ts->ucb) return -ENODEV; ts->adcsync = adcsync; init_MUTEX(&ts->sem);#ifdef CONFIG_PM ts->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ucb1x00_ts_pm); if (ts->pmdev == NULL) printk("ucb1x00_ts: unable to register in PM.\n"); else ts->pmdev->data = ts;#endif return ucb1x00_ts_register(ts);}static void __exit ucb1x00_ts_exit(void){ struct ucb1x00_ts *ts = &ucbts; ucb1x00_ts_deregister(ts);#ifdef CONFIG_PM if (ts->pmdev) pm_unregister(ts->pmdev);#endif}#ifndef MODULE/* * Parse kernel command-line options. * * syntax : ucbts=[sync|nosync],... */static int __init ucb1x00_ts_setup(char *str){ char *p; while ((p = strsep(&str, ",")) != NULL) { if (strcmp(p, "sync") == 0) adcsync = UCB_SYNC; } return 1;}__setup("ucbts=", ucb1x00_ts_setup);#elseMODULE_PARM(adcsync, "i");MODULE_PARM_DESC(adcsync, "Enable use of ADCSYNC signal");#endifmodule_init(ucb1x00_ts_init);module_exit(ucb1x00_ts_exit);MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");MODULE_DESCRIPTION("UCB1x00 touchscreen driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -