00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00039 #include <ddi.h>
00040 #include <libarch/ddi.h>
00041 #include <devmap.h>
00042 #include <io/console.h>
00043 #include <vfs/vfs.h>
00044 #include <ipc/mouse.h>
00045 #include <async.h>
00046 #include <unistd.h>
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include <sysinfo.h>
00050 #include <errno.h>
00051 #include <inttypes.h>
00052
00053 #include "s3c24xx_ts.h"
00054
00055 #define NAME "s3c24ser"
00056 #define NAMESPACE "hid_in"
00057
00058 static irq_cmd_t ts_irq_cmds[] = {
00059 {
00060 .cmd = CMD_ACCEPT
00061 }
00062 };
00063
00064 static irq_code_t ts_irq_code = {
00065 sizeof(ts_irq_cmds) / sizeof(irq_cmd_t),
00066 ts_irq_cmds
00067 };
00068
00070 static s3c24xx_ts_t *ts;
00071
00072 static void s3c24xx_ts_connection(ipc_callid_t iid, ipc_call_t *icall);
00073 static void s3c24xx_ts_irq_handler(ipc_callid_t iid, ipc_call_t *call);
00074 static void s3c24xx_ts_pen_down(s3c24xx_ts_t *ts);
00075 static void s3c24xx_ts_pen_up(s3c24xx_ts_t *ts);
00076 static void s3c24xx_ts_eoc(s3c24xx_ts_t *ts);
00077 static int s3c24xx_ts_init(s3c24xx_ts_t *ts);
00078 static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *ts, ts_updn_t updn);
00079 static void s3c24xx_ts_convert_samples(int smp0, int smp1, int *x, int *y);
00080 static int lin_map_range(int v, int i0, int i1, int o0, int o1);
00081
00082 int main(int argc, char *argv[])
00083 {
00084 int rc;
00085
00086 printf(NAME ": S3C24xx touchscreen driver\n");
00087
00088 rc = devmap_driver_register(NAME, s3c24xx_ts_connection);
00089 if (rc < 0) {
00090 printf(NAME ": Unable to register driver.\n");
00091 return -1;
00092 }
00093
00094 ts = malloc(sizeof(s3c24xx_ts_t));
00095 if (ts == NULL)
00096 return -1;
00097
00098 if (s3c24xx_ts_init(ts) != EOK)
00099 return -1;
00100
00101 rc = devmap_device_register(NAMESPACE "/mouse", &ts->devmap_handle);
00102 if (rc != EOK) {
00103 printf(NAME ": Unable to register device %s.\n",
00104 NAMESPACE "/mouse");
00105 return -1;
00106 }
00107
00108 printf(NAME ": Registered device %s.\n", NAMESPACE "/mouse");
00109
00110 printf(NAME ": Accepting connections\n");
00111 task_retval(0);
00112 async_manager();
00113
00114
00115 return 0;
00116 }
00117
00119 static int s3c24xx_ts_init(s3c24xx_ts_t *ts)
00120 {
00121 void *vaddr;
00122 sysarg_t inr;
00123
00124 inr = S3C24XX_TS_INR;
00125 ts->paddr = S3C24XX_TS_ADDR;
00126
00127 if (pio_enable((void *) ts->paddr, sizeof(s3c24xx_adc_io_t),
00128 &vaddr) != 0)
00129 return -1;
00130
00131 ts->io = vaddr;
00132 ts->client_phone = -1;
00133 ts->state = ts_wait_pendown;
00134 ts->last_x = 0;
00135 ts->last_y = 0;
00136
00137 printf(NAME ": device at physical address %p, inr %" PRIun ".\n",
00138 (void *) ts->paddr, inr);
00139
00140 async_set_interrupt_received(s3c24xx_ts_irq_handler);
00141 register_irq(inr, device_assign_devno(), 0, &ts_irq_code);
00142
00143 s3c24xx_ts_wait_for_int_mode(ts, updn_down);
00144
00145 return EOK;
00146 }
00147
00157 static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *ts, ts_updn_t updn)
00158 {
00159 uint32_t con, tsc;
00160
00161
00162
00163
00164
00165 con = pio_read_32(&ts->io->con);
00166
00167
00168 con = con & ~(ADCCON_STDBM | ADCCON_READ_START | ADCCON_ENABLE_START);
00169
00170
00171 con = con | (ADCCON_PRSCVL(0xff) << 6) | ADCCON_SEL_MUX(SMUX_XP);
00172
00173
00174 con = con | ADCCON_PRSCEN;
00175
00176 pio_write_32(&ts->io->con, con);
00177
00178
00179
00180
00181
00182 tsc = pio_read_32(&ts->io->tsc);
00183
00184
00185 if (updn == updn_up)
00186 tsc |= ADCTSC_DSUD_UP;
00187 else
00188 tsc &= ~ADCTSC_DSUD_UP;
00189
00190
00191
00192
00193
00194
00195 tsc = tsc & ~(ADCTSC_XM_ENABLE | ADCTSC_AUTO_PST |
00196 ADCTSC_PULLUP_DISABLE);
00197 tsc = tsc | ADCTSC_YP_DISABLE | ADCTSC_XP_DISABLE | ADCTSC_YM_ENABLE;
00198
00199
00200 tsc = (tsc & ~ADCTSC_XY_PST_MASK) | ADCTSC_XY_PST_WAITINT;
00201
00202 pio_write_32(&ts->io->tsc, tsc);
00203 }
00204
00206 static void s3c24xx_ts_irq_handler(ipc_callid_t iid, ipc_call_t *call)
00207 {
00208 ts_updn_t updn;
00209
00210 (void) iid; (void) call;
00211
00212
00213 updn = pio_read_32(&ts->io->updn);
00214
00215 if (updn & (ADCUPDN_TSC_DN | ADCUPDN_TSC_UP)) {
00216
00217 pio_write_32(&ts->io->updn, updn &
00218 ~(ADCUPDN_TSC_DN | ADCUPDN_TSC_UP));
00219 }
00220
00221 if (updn & ADCUPDN_TSC_DN) {
00222
00223 s3c24xx_ts_pen_down(ts);
00224 } else if (updn & ADCUPDN_TSC_UP) {
00225
00226 s3c24xx_ts_pen_up(ts);
00227 } else {
00228
00229
00230
00231 if ((pio_read_32(&ts->io->con) & ADCCON_ECFLG) == 0) {
00232 printf(NAME ": Unrecognized ts int.\n");
00233 return;
00234 }
00235
00236 if (ts->state != ts_sample_pos) {
00237
00238
00239
00240
00241 return;
00242 }
00243
00244
00245 s3c24xx_ts_eoc(ts);
00246 }
00247 }
00248
00253 static void s3c24xx_ts_pen_down(s3c24xx_ts_t *ts)
00254 {
00255
00256
00257 ts->state = ts_sample_pos;
00258
00259
00260 pio_write_32(&ts->io->tsc, (pio_read_32(&ts->io->tsc)
00261 & ~3) | 4);
00262
00263
00264 pio_write_32(&ts->io->con, pio_read_32(&ts->io->con)
00265 | ADCCON_ENABLE_START);
00266 }
00267
00272 static void s3c24xx_ts_pen_up(s3c24xx_ts_t *ts)
00273 {
00274 int button, press;
00275
00276
00277
00278 ts->state = ts_wait_pendown;
00279
00280 button = 1;
00281 press = 0;
00282 async_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
00283
00284 s3c24xx_ts_wait_for_int_mode(ts, updn_down);
00285 }
00286
00291 static void s3c24xx_ts_eoc(s3c24xx_ts_t *ts)
00292 {
00293 uint32_t data;
00294 int button, press;
00295 int smp0, smp1;
00296 int x_pos, y_pos;
00297 int dx, dy;
00298
00299 ts->state = ts_wait_penup;
00300
00301
00302
00303 data = pio_read_32(&ts->io->dat0);
00304 smp0 = data & 0x3ff;
00305
00306 data = pio_read_32(&ts->io->dat1);
00307 smp1 = data & 0x3ff;
00308
00309
00310 s3c24xx_ts_convert_samples(smp0, smp1, &x_pos, &y_pos);
00311
00312 printf("s0: 0x%03x, s1:0x%03x -> x:%d,y:%d\n", smp0, smp1,
00313 x_pos, y_pos);
00314
00315
00316 dx = x_pos - ts->last_x;
00317 dy = y_pos - ts->last_y;
00318
00319 button = 1;
00320 press = 1;
00321
00322
00323 async_msg_2(ts->client_phone, MEVENT_MOVE, dx, dy);
00324 async_msg_2(ts->client_phone, MEVENT_BUTTON, button, press);
00325
00326 ts->last_x = x_pos;
00327 ts->last_y = y_pos;
00328
00329 s3c24xx_ts_wait_for_int_mode(ts, updn_up);
00330 }
00331
00333 static void s3c24xx_ts_convert_samples(int smp0, int smp1, int *x, int *y)
00334 {
00335
00336
00337
00338
00339
00340
00341
00342
00343 *x = lin_map_range(smp1, 0xa1, 0x396, 0, 479);
00344 *y = lin_map_range(smp0, 0x69, 0x38a, 639, 0);
00345 }
00346
00360 static int lin_map_range(int v, int i0, int i1, int o0, int o1)
00361 {
00362 if (v < i0)
00363 v = i0;
00364
00365 if (v > i1)
00366 v = i1;
00367
00368 return o0 + (o1 - o0) * (v - i0) / (i1 - i0);
00369 }
00370
00372 static void s3c24xx_ts_connection(ipc_callid_t iid, ipc_call_t *icall)
00373 {
00374 ipc_callid_t callid;
00375 ipc_call_t call;
00376 int retval;
00377
00378 async_answer_0(iid, EOK);
00379
00380 while (1) {
00381 callid = async_get_call(&call);
00382 switch (IPC_GET_IMETHOD(call)) {
00383 case IPC_M_PHONE_HUNGUP:
00384 if (ts->client_phone != -1) {
00385 async_hangup(ts->client_phone);
00386 ts->client_phone = -1;
00387 }
00388
00389 async_answer_0(callid, EOK);
00390 return;
00391 case IPC_M_CONNECT_TO_ME:
00392 if (ts->client_phone != -1) {
00393 retval = ELIMIT;
00394 break;
00395 }
00396 ts->client_phone = IPC_GET_ARG5(call);
00397 retval = 0;
00398 break;
00399 default:
00400 retval = EINVAL;
00401 }
00402 async_answer_0(callid, retval);
00403 }
00404 }
00405