1 |
27 |
unneback |
//==========================================================================
|
2 |
|
|
//
|
3 |
|
|
// aaed2000_ts.c
|
4 |
|
|
//
|
5 |
|
|
// Touchscreen driver for the Agilent aaed2000
|
6 |
|
|
//
|
7 |
|
|
//==========================================================================
|
8 |
|
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
9 |
|
|
// -------------------------------------------
|
10 |
|
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
11 |
|
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
12 |
|
|
//
|
13 |
|
|
// eCos is free software; you can redistribute it and/or modify it under
|
14 |
|
|
// the terms of the GNU General Public License as published by the Free
|
15 |
|
|
// Software Foundation; either version 2 or (at your option) any later version.
|
16 |
|
|
//
|
17 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
18 |
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
20 |
|
|
// for more details.
|
21 |
|
|
//
|
22 |
|
|
// You should have received a copy of the GNU General Public License along
|
23 |
|
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
24 |
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
25 |
|
|
//
|
26 |
|
|
// As a special exception, if other files instantiate templates or use macros
|
27 |
|
|
// or inline functions from this file, or you compile this file and link it
|
28 |
|
|
// with other works to produce a work based on this file, this file does not
|
29 |
|
|
// by itself cause the resulting work to be covered by the GNU General Public
|
30 |
|
|
// License. However the source code for this file must still be made available
|
31 |
|
|
// in accordance with section (3) of the GNU General Public License.
|
32 |
|
|
//
|
33 |
|
|
// This exception does not invalidate any other reasons why a work based on
|
34 |
|
|
// this file might be covered by the GNU General Public License.
|
35 |
|
|
//
|
36 |
|
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
37 |
|
|
// at http://sources.redhat.com/ecos/ecos-license/
|
38 |
|
|
// -------------------------------------------
|
39 |
|
|
//####ECOSGPLCOPYRIGHTEND####
|
40 |
|
|
//==========================================================================
|
41 |
|
|
//#####DESCRIPTIONBEGIN####
|
42 |
|
|
//
|
43 |
|
|
// Author(s): gthomas
|
44 |
|
|
// Contributors: gthomas
|
45 |
|
|
// Date: 2002-03-05
|
46 |
|
|
// Purpose:
|
47 |
|
|
// Description: Touchscreen driver for Agilent AAED2000
|
48 |
|
|
//
|
49 |
|
|
//####DESCRIPTIONEND####
|
50 |
|
|
//
|
51 |
|
|
//==========================================================================
|
52 |
|
|
|
53 |
|
|
|
54 |
|
|
#include <pkgconf/devs_touch_aaed2000.h>
|
55 |
|
|
|
56 |
|
|
#include <cyg/kernel/kapi.h>
|
57 |
|
|
#include <cyg/hal/hal_io.h>
|
58 |
|
|
#include <cyg/hal/hal_arch.h>
|
59 |
|
|
#include <cyg/hal/drv_api.h>
|
60 |
|
|
#include <cyg/hal/hal_intr.h>
|
61 |
|
|
#include <cyg/hal/aaed2000.h>
|
62 |
|
|
#include <cyg/infra/cyg_type.h>
|
63 |
|
|
#include <cyg/infra/cyg_ass.h>
|
64 |
|
|
#include <cyg/infra/diag.h>
|
65 |
|
|
|
66 |
|
|
#include <cyg/fileio/fileio.h> // For select() functionality
|
67 |
|
|
static cyg_selinfo ts_select_info;
|
68 |
|
|
static cyg_bool ts_select_active;
|
69 |
|
|
|
70 |
|
|
#include <cyg/io/devtab.h>
|
71 |
|
|
|
72 |
|
|
/* ADS7846 flags */
|
73 |
|
|
#define ADS_START (1 << 7)
|
74 |
|
|
#define ADS_MEASURE_Y (0x01 << 4)
|
75 |
|
|
#define ADS_MEASURE_X (0x05 << 4)
|
76 |
|
|
#define ADS_MODE_12_BIT 0
|
77 |
|
|
#define ADS_PD0 0
|
78 |
|
|
|
79 |
|
|
// Misc constants
|
80 |
|
|
#define TS_INT (1<<0)
|
81 |
|
|
#define X_THRESHOLD 0x80
|
82 |
|
|
#define Y_THRESHOLD 0x80
|
83 |
|
|
|
84 |
|
|
// Functions in this module
|
85 |
|
|
|
86 |
|
|
static Cyg_ErrNo ts_read(cyg_io_handle_t handle,
|
87 |
|
|
void *buffer,
|
88 |
|
|
cyg_uint32 *len);
|
89 |
|
|
static cyg_bool ts_select(cyg_io_handle_t handle,
|
90 |
|
|
cyg_uint32 which,
|
91 |
|
|
cyg_addrword_t info);
|
92 |
|
|
static Cyg_ErrNo ts_set_config(cyg_io_handle_t handle,
|
93 |
|
|
cyg_uint32 key,
|
94 |
|
|
const void *buffer,
|
95 |
|
|
cyg_uint32 *len);
|
96 |
|
|
static Cyg_ErrNo ts_get_config(cyg_io_handle_t handle,
|
97 |
|
|
cyg_uint32 key,
|
98 |
|
|
void *buffer,
|
99 |
|
|
cyg_uint32 *len);
|
100 |
|
|
static bool ts_init(struct cyg_devtab_entry *tab);
|
101 |
|
|
static Cyg_ErrNo ts_lookup(struct cyg_devtab_entry **tab,
|
102 |
|
|
struct cyg_devtab_entry *st,
|
103 |
|
|
const char *name);
|
104 |
|
|
|
105 |
|
|
CHAR_DEVIO_TABLE(aaed2000_ts_handlers,
|
106 |
|
|
NULL, // Unsupported write() function
|
107 |
|
|
ts_read,
|
108 |
|
|
ts_select,
|
109 |
|
|
ts_get_config,
|
110 |
|
|
ts_set_config);
|
111 |
|
|
|
112 |
|
|
CHAR_DEVTAB_ENTRY(aaed2000_ts_device,
|
113 |
|
|
CYGDAT_DEVS_TOUCH_AAED2000_NAME,
|
114 |
|
|
NULL, // Base device name
|
115 |
|
|
&aaed2000_ts_handlers,
|
116 |
|
|
ts_init,
|
117 |
|
|
ts_lookup,
|
118 |
|
|
NULL); // Private data pointer
|
119 |
|
|
|
120 |
|
|
struct _event {
|
121 |
|
|
short button_state;
|
122 |
|
|
short xPos, yPos;
|
123 |
|
|
short _unused;
|
124 |
|
|
};
|
125 |
|
|
#define MAX_EVENTS CYGNUM_DEVS_TOUCH_AAED2000_EVENT_BUFFER_SIZE
|
126 |
|
|
static int num_events;
|
127 |
|
|
static int _event_put, _event_get;
|
128 |
|
|
static struct _event _events[MAX_EVENTS];
|
129 |
|
|
|
130 |
|
|
static bool _is_open = false;
|
131 |
|
|
#ifdef DEBUG_RAW_EVENTS
|
132 |
|
|
static unsigned char _ts_buf[512];
|
133 |
|
|
static int _ts_buf_ptr = 0;
|
134 |
|
|
#endif
|
135 |
|
|
|
136 |
|
|
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
|
137 |
|
|
static char ts_scan_stack[STACK_SIZE];
|
138 |
|
|
static cyg_thread ts_scan_thread_data;
|
139 |
|
|
static cyg_handle_t ts_scan_thread_handle;
|
140 |
|
|
#define SCAN_FREQ 20 // Hz
|
141 |
|
|
//#define SCAN_FREQ 5 // Hz
|
142 |
|
|
#define SCAN_DELAY ((1000/SCAN_FREQ)/10)
|
143 |
|
|
|
144 |
|
|
|
145 |
|
|
typedef struct {
|
146 |
|
|
short min;
|
147 |
|
|
short max;
|
148 |
|
|
short span;
|
149 |
|
|
} bounds;
|
150 |
|
|
|
151 |
|
|
static bounds xBounds = {1024, 0, 1024};
|
152 |
|
|
static bounds yBounds = {1024, 0, 1024};
|
153 |
|
|
|
154 |
|
|
static Cyg_ErrNo
|
155 |
|
|
ts_read(cyg_io_handle_t handle,
|
156 |
|
|
void *buffer,
|
157 |
|
|
cyg_uint32 *len)
|
158 |
|
|
{
|
159 |
|
|
struct _event *ev;
|
160 |
|
|
int tot = *len;
|
161 |
|
|
unsigned char *bp = (unsigned char *)buffer;
|
162 |
|
|
|
163 |
|
|
cyg_scheduler_lock(); // Prevent interaction with DSR code
|
164 |
|
|
while (tot >= sizeof(struct _event)) {
|
165 |
|
|
if (num_events > 0) {
|
166 |
|
|
ev = &_events[_event_get++];
|
167 |
|
|
if (_event_get == MAX_EVENTS) {
|
168 |
|
|
_event_get = 0;
|
169 |
|
|
}
|
170 |
|
|
// Self calibrate
|
171 |
|
|
if (ev->xPos > xBounds.max) xBounds.max = ev->xPos;
|
172 |
|
|
if (ev->xPos < xBounds.min) xBounds.min = ev->xPos;
|
173 |
|
|
if (ev->yPos > yBounds.max) yBounds.max = ev->yPos;
|
174 |
|
|
if (ev->yPos < yBounds.min) yBounds.min = ev->yPos;
|
175 |
|
|
if ((xBounds.span = xBounds.max - xBounds.min) <= 1) {
|
176 |
|
|
xBounds.span = 1;
|
177 |
|
|
}
|
178 |
|
|
if ((yBounds.span = yBounds.max - yBounds.min) <= 1) {
|
179 |
|
|
yBounds.span = 1;
|
180 |
|
|
}
|
181 |
|
|
// Scale values - done here so these potentially lengthy
|
182 |
|
|
// operations take place outside of interrupt processing
|
183 |
|
|
#ifdef DEBUG
|
184 |
|
|
diag_printf("Raw[%d,%d], X[%d,%d,%d], Y[%d,%d,%d]",
|
185 |
|
|
ev->xPos, ev->yPos,
|
186 |
|
|
xBounds.max, xBounds.min, xBounds.span,
|
187 |
|
|
yBounds.max, yBounds.min, yBounds.span);
|
188 |
|
|
#endif
|
189 |
|
|
ev->xPos = 640 - (((xBounds.max - ev->xPos) * 640) / xBounds.span);
|
190 |
|
|
ev->yPos = 480 - (((yBounds.max - ev->yPos) * 480) / yBounds.span);
|
191 |
|
|
#ifdef DEBUG
|
192 |
|
|
diag_printf(", Cooked[%d,%d]\n",
|
193 |
|
|
ev->xPos, ev->yPos);
|
194 |
|
|
#endif
|
195 |
|
|
memcpy(bp, ev, sizeof(*ev));
|
196 |
|
|
bp += sizeof(*ev);
|
197 |
|
|
tot -= sizeof(*ev);
|
198 |
|
|
num_events--;
|
199 |
|
|
} else {
|
200 |
|
|
break; // No more events
|
201 |
|
|
}
|
202 |
|
|
}
|
203 |
|
|
cyg_scheduler_unlock(); // Allow DSRs again
|
204 |
|
|
*len -= tot;
|
205 |
|
|
return ENOERR;
|
206 |
|
|
}
|
207 |
|
|
|
208 |
|
|
static cyg_bool
|
209 |
|
|
ts_select(cyg_io_handle_t handle,
|
210 |
|
|
cyg_uint32 which,
|
211 |
|
|
cyg_addrword_t info)
|
212 |
|
|
{
|
213 |
|
|
if (which == CYG_FREAD) {
|
214 |
|
|
cyg_scheduler_lock(); // Prevent interaction with DSR code
|
215 |
|
|
if (num_events > 0) {
|
216 |
|
|
cyg_scheduler_unlock(); // Reallow interaction with DSR code
|
217 |
|
|
return true;
|
218 |
|
|
}
|
219 |
|
|
if (!ts_select_active) {
|
220 |
|
|
ts_select_active = true;
|
221 |
|
|
cyg_selrecord(info, &ts_select_info);
|
222 |
|
|
}
|
223 |
|
|
cyg_scheduler_unlock(); // Reallow interaction with DSR code
|
224 |
|
|
}
|
225 |
|
|
return false;
|
226 |
|
|
}
|
227 |
|
|
|
228 |
|
|
static Cyg_ErrNo
|
229 |
|
|
ts_set_config(cyg_io_handle_t handle,
|
230 |
|
|
cyg_uint32 key,
|
231 |
|
|
const void *buffer,
|
232 |
|
|
cyg_uint32 *len)
|
233 |
|
|
{
|
234 |
|
|
return EINVAL;
|
235 |
|
|
}
|
236 |
|
|
|
237 |
|
|
static Cyg_ErrNo
|
238 |
|
|
ts_get_config(cyg_io_handle_t handle,
|
239 |
|
|
cyg_uint32 key,
|
240 |
|
|
void *buffer,
|
241 |
|
|
cyg_uint32 *len)
|
242 |
|
|
{
|
243 |
|
|
return EINVAL;
|
244 |
|
|
}
|
245 |
|
|
|
246 |
|
|
static bool
|
247 |
|
|
ts_init(struct cyg_devtab_entry *tab)
|
248 |
|
|
{
|
249 |
|
|
cyg_uint32 _dummy;
|
250 |
|
|
|
251 |
|
|
// Initialize SSP interface
|
252 |
|
|
#if 0
|
253 |
|
|
while (*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) {
|
254 |
|
|
_dummy = *(volatile cyg_uint32 *)AAEC_SSP_DR; // Drain FIFO
|
255 |
|
|
}
|
256 |
|
|
#endif
|
257 |
|
|
*(volatile cyg_uint32 *)AAEC_SSP_CR0 =
|
258 |
|
|
(1 << AAEC_SSP_CR0_SSE) | // SSP enable
|
259 |
|
|
(37 << AAEC_SSP_CR0_SCR) | // Serial clock rate
|
260 |
|
|
(AAEC_SSP_CR0_FRF_NAT << AAEC_SSP_CR0_FRF) | // MicroWire
|
261 |
|
|
((12-1) << AAEC_SSP_CR0_SIZE); // 12 bit words
|
262 |
|
|
*(volatile cyg_uint32 *)AAEC_SSP_CR1 =
|
263 |
|
|
(1 << AAEC_SSP_CR1_FEN); // Enable FIFO
|
264 |
|
|
*(volatile cyg_uint32 *)AAEC_SSP_CPSR = 2; // Clock prescale
|
265 |
|
|
*(volatile cyg_uint32 *)AAEC_PFDDR &= ~(1<<0); // TS uses port F bit 0
|
266 |
|
|
cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_TS);
|
267 |
|
|
cyg_selinit(&ts_select_info);
|
268 |
|
|
return true;
|
269 |
|
|
}
|
270 |
|
|
|
271 |
|
|
static cyg_uint32
|
272 |
|
|
read_ts(int axis)
|
273 |
|
|
{
|
274 |
|
|
cyg_uint32 res;
|
275 |
|
|
|
276 |
|
|
*(volatile cyg_uint32 *)AAEC_SSP_DR = (axis | ADS_START | ADS_MODE_12_BIT | ADS_PD0);
|
277 |
|
|
*(volatile cyg_uint32 *)AAEC_SSP_DR = (axis | ADS_START | ADS_MODE_12_BIT);
|
278 |
|
|
// Wait for data
|
279 |
|
|
while ((*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) == 0);
|
280 |
|
|
res = *(volatile cyg_uint32 *)AAEC_SSP_DR; // ignore first datum
|
281 |
|
|
// Wait for data
|
282 |
|
|
while ((*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) == 0);
|
283 |
|
|
res = *(volatile cyg_uint32 *)AAEC_SSP_DR;
|
284 |
|
|
return res;
|
285 |
|
|
}
|
286 |
|
|
|
287 |
|
|
static void
|
288 |
|
|
ts_scan(cyg_addrword_t param)
|
289 |
|
|
{
|
290 |
|
|
short lastX, lastY;
|
291 |
|
|
short x, y;
|
292 |
|
|
struct _event *ev;
|
293 |
|
|
bool pen_down;
|
294 |
|
|
|
295 |
|
|
diag_printf("Touch Screen thread started\n");
|
296 |
|
|
// Discard the first sample - it's always 0
|
297 |
|
|
x = read_ts(ADS_MEASURE_X);
|
298 |
|
|
y = read_ts(ADS_MEASURE_Y);
|
299 |
|
|
lastX = lastY = -1;
|
300 |
|
|
pen_down = false;
|
301 |
|
|
while (true) {
|
302 |
|
|
cyg_thread_delay(SCAN_DELAY);
|
303 |
|
|
if ((*(volatile cyg_uint32 *)AAEC_PFDR & TS_INT) == 0) {
|
304 |
|
|
// Pen is down
|
305 |
|
|
x = read_ts(ADS_MEASURE_X);
|
306 |
|
|
y = read_ts(ADS_MEASURE_Y);
|
307 |
|
|
// diag_printf("X = %x, Y = %x\n", x, y);
|
308 |
|
|
if ((x < X_THRESHOLD) || (y < Y_THRESHOLD)) {
|
309 |
|
|
// Ignore 'bad' samples
|
310 |
|
|
continue;
|
311 |
|
|
}
|
312 |
|
|
lastX = x; lastY = y;
|
313 |
|
|
pen_down = true;
|
314 |
|
|
} else {
|
315 |
|
|
if (pen_down) {
|
316 |
|
|
// Capture first 'up' event
|
317 |
|
|
pen_down = false;
|
318 |
|
|
x = lastX;
|
319 |
|
|
y = lastY;
|
320 |
|
|
} else {
|
321 |
|
|
continue; // Nothing new to report
|
322 |
|
|
}
|
323 |
|
|
}
|
324 |
|
|
if (num_events < MAX_EVENTS) {
|
325 |
|
|
num_events++;
|
326 |
|
|
ev = &_events[_event_put++];
|
327 |
|
|
if (_event_put == MAX_EVENTS) {
|
328 |
|
|
_event_put = 0;
|
329 |
|
|
}
|
330 |
|
|
ev->button_state = pen_down ? 0x04 : 0x00;
|
331 |
|
|
ev->xPos = x;
|
332 |
|
|
ev->yPos = y;
|
333 |
|
|
if (ts_select_active) {
|
334 |
|
|
ts_select_active = false;
|
335 |
|
|
cyg_selwakeup(&ts_select_info);
|
336 |
|
|
}
|
337 |
|
|
}
|
338 |
|
|
#ifdef DEBUG_RAW_EVENTS
|
339 |
|
|
memcpy(&_ts_buf[_ts_buf_ptr], pkt->data, 8);
|
340 |
|
|
_ts_buf_ptr += 8;
|
341 |
|
|
if (_ts_buf_ptr == 512) {
|
342 |
|
|
diag_printf("TS handler\n");
|
343 |
|
|
diag_dump_buf(_ts_buf, 512);
|
344 |
|
|
_ts_buf_ptr = 0;
|
345 |
|
|
}
|
346 |
|
|
#endif
|
347 |
|
|
}
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
static Cyg_ErrNo
|
351 |
|
|
ts_lookup(struct cyg_devtab_entry **tab,
|
352 |
|
|
struct cyg_devtab_entry *st,
|
353 |
|
|
const char *name)
|
354 |
|
|
{
|
355 |
|
|
if (!_is_open) {
|
356 |
|
|
_is_open = true;
|
357 |
|
|
cyg_thread_create(1, // Priority
|
358 |
|
|
ts_scan, // entry
|
359 |
|
|
0, // entry parameter
|
360 |
|
|
"Touch Screen scan", // Name
|
361 |
|
|
&ts_scan_stack[0], // Stack
|
362 |
|
|
STACK_SIZE, // Size
|
363 |
|
|
&ts_scan_thread_handle, // Handle
|
364 |
|
|
&ts_scan_thread_data // Thread data structure
|
365 |
|
|
);
|
366 |
|
|
cyg_thread_resume(ts_scan_thread_handle); // Start it
|
367 |
|
|
}
|
368 |
|
|
return ENOERR;
|
369 |
|
|
}
|