HelenOS sources
This source file includes following definitions.
- main
- s3c24xx_ts_init
- s3c24xx_ts_wait_for_int_mode
- s3c24xx_ts_irq_handler
- s3c24xx_ts_pen_down
- s3c24xx_ts_pen_up
- s3c24xx_ts_eoc
- s3c24xx_ts_convert_samples
- lin_map_range
- s3c24xx_ts_connection
#include <ddi.h>
#include <loc.h>
#include <vfs/vfs.h>
#include <ipc/mouseev.h>
#include <async.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysinfo.h>
#include <errno.h>
#include <inttypes.h>
#include "s3c24xx_ts.h"
#define NAME "s3c24xx_ts"
#define NAMESPACE "hid"
static irq_cmd_t ts_irq_cmds[] = {
{
.cmd = CMD_ACCEPT
}
};
static irq_code_t ts_irq_code = {
0,
NULL,
sizeof(ts_irq_cmds) / sizeof(irq_cmd_t),
ts_irq_cmds
};
static s3c24xx_ts_t *ts;
static void s3c24xx_ts_connection(ipc_call_t *, void *);
static void s3c24xx_ts_irq_handler(ipc_call_t *, void *);
static void s3c24xx_ts_pen_down(s3c24xx_ts_t *);
static void s3c24xx_ts_pen_up(s3c24xx_ts_t *);
static void s3c24xx_ts_eoc(s3c24xx_ts_t *);
static int s3c24xx_ts_init(s3c24xx_ts_t *);
static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *, ts_updn_t);
static void s3c24xx_ts_convert_samples(int, int, int *, int *);
static int lin_map_range(int, int, int, int, int);
int main(int argc, char *argv[])
{
loc_srv_t *srv;
printf("%s: S3C24xx touchscreen driver\n", NAME);
async_set_fallback_port_handler(s3c24xx_ts_connection, NULL);
errno_t rc = loc_server_register(NAME, &srv);
if (rc != EOK) {
printf("%s: Unable to register driver.\n", NAME);
return rc;
}
ts = malloc(sizeof(s3c24xx_ts_t));
if (ts == NULL) {
loc_server_unregister(srv);
return -1;
}
if (s3c24xx_ts_init(ts) != EOK) {
free(ts);
loc_server_unregister(srv);
return -1;
}
rc = loc_service_register(srv, NAMESPACE "/mouse", &ts->service_id);
if (rc != EOK) {
free(ts);
loc_server_unregister(srv);
printf(NAME ": Unable to register device %s.\n",
NAMESPACE "/mouse");
return -1;
}
printf(NAME ": Registered device %s.\n", NAMESPACE "/mouse");
printf(NAME ": Accepting connections\n");
task_retval(0);
async_manager();
return 0;
}
static int s3c24xx_ts_init(s3c24xx_ts_t *ts)
{
void *vaddr;
sysarg_t inr;
inr = S3C24XX_TS_INR;
ts->paddr = S3C24XX_TS_ADDR;
if (pio_enable((void *) ts->paddr, sizeof(s3c24xx_adc_io_t),
&vaddr) != 0)
return -1;
ts->io = vaddr;
ts->client_sess = NULL;
ts->state = ts_wait_pendown;
ts->last_x = 0;
ts->last_y = 0;
printf(NAME ": device at physical address %p, inr %" PRIun ".\n",
(void *) ts->paddr, inr);
async_irq_subscribe(inr, s3c24xx_ts_irq_handler, NULL, &ts_irq_code, NULL);
s3c24xx_ts_wait_for_int_mode(ts, updn_down);
return EOK;
}
static void s3c24xx_ts_wait_for_int_mode(s3c24xx_ts_t *ts, ts_updn_t updn)
{
uint32_t con, tsc;
con = pio_read_32(&ts->io->con);
con = con & ~(ADCCON_STDBM | ADCCON_READ_START | ADCCON_ENABLE_START);
con = con | (ADCCON_PRSCVL(0xff) << 6) | ADCCON_SEL_MUX(SMUX_XP);
con = con | ADCCON_PRSCEN;
pio_write_32(&ts->io->con, con);
tsc = pio_read_32(&ts->io->tsc);
if (updn == updn_up)
tsc |= ADCTSC_DSUD_UP;
else
tsc &= ~ADCTSC_DSUD_UP;
tsc = tsc & ~(ADCTSC_XM_ENABLE | ADCTSC_AUTO_PST |
ADCTSC_PULLUP_DISABLE);
tsc = tsc | ADCTSC_YP_DISABLE | ADCTSC_XP_DISABLE | ADCTSC_YM_ENABLE;
tsc = (tsc & ~ADCTSC_XY_PST_MASK) | ADCTSC_XY_PST_WAITINT;
pio_write_32(&ts->io->tsc, tsc);
}
static void s3c24xx_ts_irq_handler(ipc_call_t *call, void *arg)
{
ts_updn_t updn;
(void) call;
updn = pio_read_32(&ts->io->updn);
if (updn & (ADCUPDN_TSC_DN | ADCUPDN_TSC_UP)) {
pio_write_32(&ts->io->updn, updn &
~(ADCUPDN_TSC_DN | ADCUPDN_TSC_UP));
}
if (updn & ADCUPDN_TSC_DN) {
s3c24xx_ts_pen_down(ts);
} else if (updn & ADCUPDN_TSC_UP) {
s3c24xx_ts_pen_up(ts);
} else {
if ((pio_read_32(&ts->io->con) & ADCCON_ECFLG) == 0) {
printf(NAME ": Unrecognized ts int.\n");
return;
}
if (ts->state != ts_sample_pos) {
return;
}
s3c24xx_ts_eoc(ts);
}
}
static void s3c24xx_ts_pen_down(s3c24xx_ts_t *ts)
{
ts->state = ts_sample_pos;
pio_write_32(&ts->io->tsc, (pio_read_32(&ts->io->tsc) & ~3) | 4);
pio_write_32(&ts->io->con, pio_read_32(&ts->io->con) | ADCCON_ENABLE_START);
}
static void s3c24xx_ts_pen_up(s3c24xx_ts_t *ts)
{
int button, press;
ts->state = ts_wait_pendown;
button = 1;
press = 0;
async_exch_t *exch = async_exchange_begin(ts->client_sess);
async_msg_2(exch, MOUSEEV_BUTTON_EVENT, button, press);
async_exchange_end(exch);
s3c24xx_ts_wait_for_int_mode(ts, updn_down);
}
static void s3c24xx_ts_eoc(s3c24xx_ts_t *ts)
{
uint32_t data;
int button, press;
int smp0, smp1;
int x_pos, y_pos;
int dx, dy;
ts->state = ts_wait_penup;
data = pio_read_32(&ts->io->dat0);
smp0 = data & 0x3ff;
data = pio_read_32(&ts->io->dat1);
smp1 = data & 0x3ff;
s3c24xx_ts_convert_samples(smp0, smp1, &x_pos, &y_pos);
printf("s0: 0x%03x, s1:0x%03x -> x:%d,y:%d\n", smp0, smp1,
x_pos, y_pos);
dx = x_pos - ts->last_x;
dy = y_pos - ts->last_y;
button = 1;
press = 1;
async_exch_t *exch = async_exchange_begin(ts->client_sess);
async_msg_2(exch, MOUSEEV_MOVE_EVENT, dx, dy);
async_msg_2(exch, MOUSEEV_BUTTON_EVENT, button, press);
async_exchange_end(exch);
ts->last_x = x_pos;
ts->last_y = y_pos;
s3c24xx_ts_wait_for_int_mode(ts, updn_up);
}
static void s3c24xx_ts_convert_samples(int smp0, int smp1, int *x, int *y)
{
*x = lin_map_range(smp1, 0xa1, 0x396, 0, 479);
*y = lin_map_range(smp0, 0x69, 0x38a, 639, 0);
}
static int lin_map_range(int v, int i0, int i1, int o0, int o1)
{
if (v < i0)
v = i0;
if (v > i1)
v = i1;
return o0 + (o1 - o0) * (v - i0) / (i1 - i0);
}
static void s3c24xx_ts_connection(ipc_call_t *icall, void *arg)
{
async_accept_0(icall);
while (true) {
ipc_call_t call;
async_get_call(&call);
if (!ipc_get_imethod(&call)) {
if (ts->client_sess != NULL) {
async_hangup(ts->client_sess);
ts->client_sess = NULL;
}
async_answer_0(&call, EOK);
return;
}
async_sess_t *sess =
async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
if (sess != NULL) {
if (ts->client_sess == NULL) {
ts->client_sess = sess;
async_answer_0(&call, EOK);
} else
async_answer_0(&call, ELIMIT);
} else
async_answer_0(&call, EINVAL);
}
}
HelenOS homepage, sources at GitHub