source: mainline/uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c@ 9ab4026

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9ab4026 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup mouse
30 * @{
31 */
32/**
33 * @file
34 * @brief Samsung Samsung S3C24xx on-chip ADC and touch-screen interface driver.
35 *
36 * This interface is present on the Samsung S3C24xx CPU (on the gta02 platform).
37 */
38
39#include <ddi.h>
40#include <loc.h>
41#include <io/console.h>
42#include <vfs/vfs.h>
43#include <ipc/mouseev.h>
44#include <async.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <sysinfo.h>
48#include <errno.h>
49#include <inttypes.h>
50#include "s3c24xx_ts.h"
51
52#define NAME "s3c24xx_ts"
53#define NAMESPACE "hid"
54
55static irq_cmd_t ts_irq_cmds[] = {
56 {
57 .cmd = CMD_ACCEPT
58 }
59};
60
61static irq_code_t ts_irq_code = {
62 0,
63 NULL,
64 sizeof(ts_irq_cmds) / sizeof(irq_cmd_t),
65 ts_irq_cmds
66};
67
68/** S3C24xx touchscreen instance structure */
69static s3c24xx_ts_t *ts;
70
71static void s3c24xx_ts_connection(ipc_call_t *, void *);
72static void s3c24xx_ts_irq_handler(ipc_call_t *, void *);
73static void s3c24xx_ts_pen_down(s3c24xx_ts_t *);
74static void s3c24xx_ts_pen_up(s3c24xx_ts_t *);
75static void s3c24xx_ts_eoc(s3c24xx_ts_t *);
76static int s3c24xx_ts_init(s3c24xx_ts_t *);
77static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *, ts_updn_t);
78static void s3c24xx_ts_convert_samples(int, int, int *, int *);
79static int lin_map_range(int, int, int, int, int);
80
81int main(int argc, char *argv[])
82{
83 printf("%s: S3C24xx touchscreen driver\n", NAME);
84
85 async_set_fallback_port_handler(s3c24xx_ts_connection, NULL);
86 errno_t rc = loc_server_register(NAME);
87 if (rc != EOK) {
88 printf("%s: Unable to register driver.\n", NAME);
89 return rc;
90 }
91
92 ts = malloc(sizeof(s3c24xx_ts_t));
93 if (ts == NULL)
94 return -1;
95
96 if (s3c24xx_ts_init(ts) != EOK)
97 return -1;
98
99 rc = loc_service_register(NAMESPACE "/mouse", &ts->service_id);
100 if (rc != EOK) {
101 printf(NAME ": Unable to register device %s.\n",
102 NAMESPACE "/mouse");
103 return -1;
104 }
105
106 printf(NAME ": Registered device %s.\n", NAMESPACE "/mouse");
107
108 printf(NAME ": Accepting connections\n");
109 task_retval(0);
110 async_manager();
111
112 /* Not reached */
113 return 0;
114}
115
116/** Initialize S3C24xx touchscreen interface. */
117static int s3c24xx_ts_init(s3c24xx_ts_t *ts)
118{
119 void *vaddr;
120 sysarg_t inr;
121
122 inr = S3C24XX_TS_INR;
123 ts->paddr = S3C24XX_TS_ADDR;
124
125 if (pio_enable((void *) ts->paddr, sizeof(s3c24xx_adc_io_t),
126 &vaddr) != 0)
127 return -1;
128
129 ts->io = vaddr;
130 ts->client_sess = NULL;
131 ts->state = ts_wait_pendown;
132 ts->last_x = 0;
133 ts->last_y = 0;
134
135 printf(NAME ": device at physical address %p, inr %" PRIun ".\n",
136 (void *) ts->paddr, inr);
137
138 async_irq_subscribe(inr, s3c24xx_ts_irq_handler, NULL, &ts_irq_code, NULL);
139
140 s3c24xx_ts_wait_for_int_mode(ts, updn_down);
141
142 return EOK;
143}
144
145/** Switch interface to wait for interrupt mode.
146 *
147 * In this mode we receive an interrupt when pen goes up/down, depending
148 * on @a updn.
149 *
150 * @param ts Touchscreen instance
151 * @param updn @c updn_up to wait for pen up, @c updn_down to wait for pen
152 * down.
153 */
154static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *ts, ts_updn_t updn)
155{
156 uint32_t con, tsc;
157
158 /*
159 * Configure ADCCON register
160 */
161
162 con = pio_read_32(&ts->io->con);
163
164 /* Disable standby, disable start-by-read, clear manual start bit */
165 con = con & ~(ADCCON_STDBM | ADCCON_READ_START | ADCCON_ENABLE_START);
166
167 /* Set prescaler value 0xff, XP for input. */
168 con = con | (ADCCON_PRSCVL(0xff) << 6) | ADCCON_SEL_MUX(SMUX_XP);
169
170 /* Enable prescaler. */
171 con = con | ADCCON_PRSCEN;
172
173 pio_write_32(&ts->io->con, con);
174
175 /*
176 * Configure ADCTSC register
177 */
178
179 tsc = pio_read_32(&ts->io->tsc);
180
181 /* Select whether waiting for pen up or pen down. */
182 if (updn == updn_up)
183 tsc |= ADCTSC_DSUD_UP;
184 else
185 tsc &= ~ADCTSC_DSUD_UP;
186
187 /*
188 * Enable XP pull-up and disable all drivers except YM. This is
189 * according to the manual. This gives us L on XP input when touching
190 * and (pulled up to) H when not touching.
191 */
192 tsc = tsc & ~(ADCTSC_XM_ENABLE | ADCTSC_AUTO_PST |
193 ADCTSC_PULLUP_DISABLE);
194 tsc = tsc | ADCTSC_YP_DISABLE | ADCTSC_XP_DISABLE | ADCTSC_YM_ENABLE;
195
196 /* Select wait-for-interrupt mode. */
197 tsc = (tsc & ~ADCTSC_XY_PST_MASK) | ADCTSC_XY_PST_WAITINT;
198
199 pio_write_32(&ts->io->tsc, tsc);
200}
201
202/** Handle touchscreen interrupt */
203static void s3c24xx_ts_irq_handler(ipc_call_t *call, void *arg)
204{
205 ts_updn_t updn;
206
207 (void) call;
208
209 /* Read up/down interrupt flags. */
210 updn = pio_read_32(&ts->io->updn);
211
212 if (updn & (ADCUPDN_TSC_DN | ADCUPDN_TSC_UP)) {
213 /* Clear up/down interrupt flags. */
214 pio_write_32(&ts->io->updn, updn &
215 ~(ADCUPDN_TSC_DN | ADCUPDN_TSC_UP));
216 }
217
218 if (updn & ADCUPDN_TSC_DN) {
219 /* Pen-down interrupt */
220 s3c24xx_ts_pen_down(ts);
221 } else if (updn & ADCUPDN_TSC_UP) {
222 /* Pen-up interrupt */
223 s3c24xx_ts_pen_up(ts);
224 } else {
225 /* Presumably end-of-conversion interrupt */
226
227 /* Check end-of-conversion flag. */
228 if ((pio_read_32(&ts->io->con) & ADCCON_ECFLG) == 0) {
229 printf(NAME ": Unrecognized ts int.\n");
230 return;
231 }
232
233 if (ts->state != ts_sample_pos) {
234 /*
235 * We got an extra interrupt ater switching to
236 * wait for interrupt mode.
237 */
238 return;
239 }
240
241 /* End-of-conversion interrupt */
242 s3c24xx_ts_eoc(ts);
243 }
244}
245
246/** Handle pen-down interrupt.
247 *
248 * @param ts Touchscreen instance
249 */
250static void s3c24xx_ts_pen_down(s3c24xx_ts_t *ts)
251{
252 /* Pen-down interrupt */
253
254 ts->state = ts_sample_pos;
255
256 /* Enable auto xy-conversion mode */
257 pio_write_32(&ts->io->tsc, (pio_read_32(&ts->io->tsc) & ~3) | 4);
258
259 /* Start the conversion. */
260 pio_write_32(&ts->io->con, pio_read_32(&ts->io->con) | ADCCON_ENABLE_START);
261}
262
263/** Handle pen-up interrupt.
264 *
265 * @param ts Touchscreen instance
266 */
267static void s3c24xx_ts_pen_up(s3c24xx_ts_t *ts)
268{
269 int button, press;
270
271 /* Pen-up interrupt */
272
273 ts->state = ts_wait_pendown;
274
275 button = 1;
276 press = 0;
277
278 async_exch_t *exch = async_exchange_begin(ts->client_sess);
279 async_msg_2(exch, MOUSEEV_BUTTON_EVENT, button, press);
280 async_exchange_end(exch);
281
282 s3c24xx_ts_wait_for_int_mode(ts, updn_down);
283}
284
285/** Handle end-of-conversion interrupt.
286 *
287 * @param ts Touchscreen instance
288 */
289static void s3c24xx_ts_eoc(s3c24xx_ts_t *ts)
290{
291 uint32_t data;
292 int button, press;
293 int smp0, smp1;
294 int x_pos, y_pos;
295 int dx, dy;
296
297 ts->state = ts_wait_penup;
298
299 /* Read in sampled data. */
300
301 data = pio_read_32(&ts->io->dat0);
302 smp0 = data & 0x3ff;
303
304 data = pio_read_32(&ts->io->dat1);
305 smp1 = data & 0x3ff;
306
307 /* Convert to screen coordinates. */
308 s3c24xx_ts_convert_samples(smp0, smp1, &x_pos, &y_pos);
309
310 printf("s0: 0x%03x, s1:0x%03x -> x:%d,y:%d\n", smp0, smp1,
311 x_pos, y_pos);
312
313 /* Get differences. */
314 dx = x_pos - ts->last_x;
315 dy = y_pos - ts->last_y;
316
317 button = 1;
318 press = 1;
319
320 /* Send notifications to client. */
321 async_exch_t *exch = async_exchange_begin(ts->client_sess);
322 async_msg_2(exch, MOUSEEV_MOVE_EVENT, dx, dy);
323 async_msg_2(exch, MOUSEEV_BUTTON_EVENT, button, press);
324 async_exchange_end(exch);
325
326 ts->last_x = x_pos;
327 ts->last_y = y_pos;
328
329 s3c24xx_ts_wait_for_int_mode(ts, updn_up);
330}
331
332/** Convert sampled data to screen coordinates. */
333static void s3c24xx_ts_convert_samples(int smp0, int smp1, int *x, int *y)
334{
335 /*
336 * The orientation and display dimensions are GTA02-specific and the
337 * calibration values might even specific to the individual piece
338 * of hardware.
339 *
340 * The calibration values can be obtained by touching corners
341 * of the screen with the stylus and noting the sampled values.
342 */
343 *x = lin_map_range(smp1, 0xa1, 0x396, 0, 479);
344 *y = lin_map_range(smp0, 0x69, 0x38a, 639, 0);
345}
346
347/** Map integer from one range to another range in a linear fashion.
348 *
349 * i0 < i1 is required. i0 is mapped to o0, i1 to o1. If o1 < o0, then the
350 * mapping will be descending. If v is outside of [i0, i1], it is clamped.
351 *
352 * @param v Value to map.
353 * @param i0 Lower bound of input range.
354 * @param i1 Upper bound of input range.
355 * @param o0 First bound of output range.
356 * @param o1 Second bound of output range.
357 *
358 * @return Mapped value ov, o0 <= ov <= o1.
359 */
360static int lin_map_range(int v, int i0, int i1, int o0, int o1)
361{
362 if (v < i0)
363 v = i0;
364
365 if (v > i1)
366 v = i1;
367
368 return o0 + (o1 - o0) * (v - i0) / (i1 - i0);
369}
370
371/** Handle mouse client connection. */
372static void s3c24xx_ts_connection(ipc_call_t *icall, void *arg)
373{
374 async_answer_0(icall, EOK);
375
376 while (true) {
377 ipc_call_t call;
378 async_get_call(&call);
379
380 if (!IPC_GET_IMETHOD(call)) {
381 if (ts->client_sess != NULL) {
382 async_hangup(ts->client_sess);
383 ts->client_sess = NULL;
384 }
385
386 async_answer_0(&call, EOK);
387 return;
388 }
389
390 async_sess_t *sess =
391 async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
392 if (sess != NULL) {
393 if (ts->client_sess == NULL) {
394 ts->client_sess = sess;
395 async_answer_0(&call, EOK);
396 } else
397 async_answer_0(&call, ELIMIT);
398 } else
399 async_answer_0(&call, EINVAL);
400 }
401}
402
403/** @}
404 */
Note: See TracBrowser for help on using the repository browser.