📄 tsc210x.c
字号:
static uint16_t tsc210x_read(struct tsc210x_state_s *s){ uint16_t ret = 0x0000; if (!s->command) fprintf(stderr, "tsc210x_read: SPI underrun!\n"); switch (s->page) { case TSC_DATA_REGISTERS_PAGE: ret = tsc2102_data_register_read(s, s->offset); if (!s->dav) qemu_irq_raise(s->davint); break; case TSC_CONTROL_REGISTERS_PAGE: ret = tsc2102_control_register_read(s, s->offset); break; case TSC_AUDIO_REGISTERS_PAGE: ret = tsc2102_audio_register_read(s, s->offset); break; default: cpu_abort(cpu_single_env, "tsc210x_read: wrong memory page\n"); } tsc210x_pin_update(s); /* Allow sequential reads. */ s->offset ++; s->state = 0; return ret;}static void tsc210x_write(struct tsc210x_state_s *s, uint16_t value){ /* * This is a two-state state machine for reading * command and data every second time. */ if (!s->state) { s->command = value >> 15; s->page = (value >> 11) & 0x0f; s->offset = (value >> 5) & 0x3f; s->state = 1; } else { if (s->command) fprintf(stderr, "tsc210x_write: SPI overrun!\n"); else switch (s->page) { case TSC_DATA_REGISTERS_PAGE: tsc2102_data_register_write(s, s->offset, value); break; case TSC_CONTROL_REGISTERS_PAGE: tsc2102_control_register_write(s, s->offset, value); break; case TSC_AUDIO_REGISTERS_PAGE: tsc2102_audio_register_write(s, s->offset, value); break; default: cpu_abort(cpu_single_env, "tsc210x_write: wrong memory page\n"); } tsc210x_pin_update(s); s->state = 0; }}uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len){ struct tsc210x_state_s *s = opaque; uint32_t ret = 0; if (len != 16) cpu_abort(cpu_single_env, "%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len); /* TODO: sequential reads etc - how do we make sure the host doesn't * unintentionally read out a conversion result from a register while * transmitting the command word of the next command? */ if (!value || (s->state && s->command)) ret = tsc210x_read(s); if (value || (s->state && !s->command)) tsc210x_write(s, value); return ret;}static void tsc210x_timer_tick(void *opaque){ struct tsc210x_state_s *s = opaque; /* Timer ticked -- a set of conversions has been finished. */ if (!s->busy) return; s->busy = 0; s->dav |= mode_regs[s->function]; tsc210x_pin_update(s); qemu_irq_lower(s->davint);}static void tsc210x_touchscreen_event(void *opaque, int x, int y, int z, int buttons_state){ struct tsc210x_state_s *s = opaque; int p = s->pressure; if (buttons_state) { s->x = x; s->y = y; } s->pressure = !!buttons_state; /* * Note: We would get better responsiveness in the guest by * signaling TS events immediately, but for now we simulate * the first conversion delay for sake of correctness. */ if (p != s->pressure) tsc210x_pin_update(s);}static void tsc210x_i2s_swallow(struct tsc210x_state_s *s){ if (s->dac_voice[0]) tsc210x_out_flush(s, s->codec.out.len); else s->codec.out.len = 0;}static void tsc210x_i2s_set_rate(struct tsc210x_state_s *s, int in, int out){ s->i2s_tx_rate = out; s->i2s_rx_rate = in;}static void tsc210x_save(QEMUFile *f, void *opaque){ struct tsc210x_state_s *s = (struct tsc210x_state_s *) opaque; int64_t now = qemu_get_clock(vm_clock); int i; qemu_put_be16(f, s->x); qemu_put_be16(f, s->y); qemu_put_byte(f, s->pressure); qemu_put_byte(f, s->state); qemu_put_byte(f, s->page); qemu_put_byte(f, s->offset); qemu_put_byte(f, s->command); qemu_put_byte(f, s->irq); qemu_put_be16s(f, &s->dav); qemu_put_timer(f, s->timer); qemu_put_byte(f, s->enabled); qemu_put_byte(f, s->host_mode); qemu_put_byte(f, s->function); qemu_put_byte(f, s->nextfunction); qemu_put_byte(f, s->precision); qemu_put_byte(f, s->nextprecision); qemu_put_byte(f, s->filter); qemu_put_byte(f, s->pin_func); qemu_put_byte(f, s->ref); qemu_put_byte(f, s->timing); qemu_put_be32(f, s->noise); qemu_put_be16s(f, &s->audio_ctrl1); qemu_put_be16s(f, &s->audio_ctrl2); qemu_put_be16s(f, &s->audio_ctrl3); qemu_put_be16s(f, &s->pll[0]); qemu_put_be16s(f, &s->pll[1]); qemu_put_be16s(f, &s->volume); qemu_put_be64(f, (uint64_t) (s->volume_change - now)); qemu_put_be64(f, (uint64_t) (s->powerdown - now)); qemu_put_byte(f, s->softstep); qemu_put_be16s(f, &s->dac_power); for (i = 0; i < 0x14; i ++) qemu_put_be16s(f, &s->filter_data[i]);}static int tsc210x_load(QEMUFile *f, void *opaque, int version_id){ struct tsc210x_state_s *s = (struct tsc210x_state_s *) opaque; int64_t now = qemu_get_clock(vm_clock); int i; s->x = qemu_get_be16(f); s->y = qemu_get_be16(f); s->pressure = qemu_get_byte(f); s->state = qemu_get_byte(f); s->page = qemu_get_byte(f); s->offset = qemu_get_byte(f); s->command = qemu_get_byte(f); s->irq = qemu_get_byte(f); qemu_get_be16s(f, &s->dav); qemu_get_timer(f, s->timer); s->enabled = qemu_get_byte(f); s->host_mode = qemu_get_byte(f); s->function = qemu_get_byte(f); s->nextfunction = qemu_get_byte(f); s->precision = qemu_get_byte(f); s->nextprecision = qemu_get_byte(f); s->filter = qemu_get_byte(f); s->pin_func = qemu_get_byte(f); s->ref = qemu_get_byte(f); s->timing = qemu_get_byte(f); s->noise = qemu_get_be32(f); qemu_get_be16s(f, &s->audio_ctrl1); qemu_get_be16s(f, &s->audio_ctrl2); qemu_get_be16s(f, &s->audio_ctrl3); qemu_get_be16s(f, &s->pll[0]); qemu_get_be16s(f, &s->pll[1]); qemu_get_be16s(f, &s->volume); s->volume_change = (int64_t) qemu_get_be64(f) + now; s->powerdown = (int64_t) qemu_get_be64(f) + now; s->softstep = qemu_get_byte(f); qemu_get_be16s(f, &s->dac_power); for (i = 0; i < 0x14; i ++) qemu_get_be16s(f, &s->filter_data[i]); s->busy = qemu_timer_pending(s->timer); qemu_set_irq(s->pint, !s->irq); qemu_set_irq(s->davint, !s->dav); return 0;}static int tsc2102_iid = 0;struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio){ struct tsc210x_state_s *s; s = (struct tsc210x_state_s *) qemu_mallocz(sizeof(struct tsc210x_state_s)); memset(s, 0, sizeof(struct tsc210x_state_s)); s->x = 160; s->y = 160; s->pressure = 0; s->precision = s->nextprecision = 0; s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); s->pint = pint; s->model = 0x2102; s->name = "tsc2102"; s->audio = audio; s->tr[0] = 0; s->tr[1] = 1; s->tr[2] = 1; s->tr[3] = 0; s->tr[4] = 1; s->tr[5] = 0; s->tr[6] = 1; s->tr[7] = 0; s->chip.opaque = s; s->chip.send = (void *) tsc210x_write; s->chip.receive = (void *) tsc210x_read; s->codec.opaque = s; s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; s->codec.set_rate = (void *) tsc210x_i2s_set_rate; s->codec.in.fifo = s->in_fifo; s->codec.out.fifo = s->out_fifo; tsc210x_reset(s); qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, "QEMU TSC2102-driven Touchscreen"); if (s->audio) AUD_register_card(s->audio, s->name, &s->card); qemu_register_reset((void *) tsc210x_reset, s); register_savevm(s->name, tsc2102_iid ++, 0, tsc210x_save, tsc210x_load, s); return &s->chip;}struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav, AudioState *audio){ struct tsc210x_state_s *s; s = (struct tsc210x_state_s *) qemu_mallocz(sizeof(struct tsc210x_state_s)); memset(s, 0, sizeof(struct tsc210x_state_s)); s->x = 400; s->y = 240; s->pressure = 0; s->precision = s->nextprecision = 0; s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); s->pint = penirq; s->kbint = kbirq; s->davint = dav; s->model = 0x2301; s->name = "tsc2301"; s->audio = audio; s->tr[0] = 0; s->tr[1] = 1; s->tr[2] = 1; s->tr[3] = 0; s->tr[4] = 1; s->tr[5] = 0; s->tr[6] = 1; s->tr[7] = 0; s->chip.opaque = s; s->chip.send = (void *) tsc210x_write; s->chip.receive = (void *) tsc210x_read; s->codec.opaque = s; s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; s->codec.set_rate = (void *) tsc210x_i2s_set_rate; s->codec.in.fifo = s->in_fifo; s->codec.out.fifo = s->out_fifo; tsc210x_reset(s); qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, "QEMU TSC2301-driven Touchscreen"); if (s->audio) AUD_register_card(s->audio, s->name, &s->card); qemu_register_reset((void *) tsc210x_reset, s); register_savevm(s->name, tsc2102_iid ++, 0, tsc210x_save, tsc210x_load, s); return &s->chip;}struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip){ struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; return &s->codec;}/* * Use tslib generated calibration data to generate ADC input values * from the touchscreen. Assuming 12-bit precision was used during * tslib calibration. */void tsc210x_set_transform(struct uwire_slave_s *chip, struct mouse_transform_info_s *info){ struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque;#if 0 int64_t ltr[8]; ltr[0] = (int64_t) info->a[1] * info->y; ltr[1] = (int64_t) info->a[4] * info->x; ltr[2] = (int64_t) info->a[1] * info->a[3] - (int64_t) info->a[4] * info->a[0]; ltr[3] = (int64_t) info->a[2] * info->a[4] - (int64_t) info->a[5] * info->a[1]; ltr[4] = (int64_t) info->a[0] * info->y; ltr[5] = (int64_t) info->a[3] * info->x; ltr[6] = (int64_t) info->a[4] * info->a[0] - (int64_t) info->a[1] * info->a[3]; ltr[7] = (int64_t) info->a[2] * info->a[3] - (int64_t) info->a[5] * info->a[0]; /* Avoid integer overflow */ s->tr[0] = ltr[0] >> 11; s->tr[1] = ltr[1] >> 11; s->tr[2] = muldiv64(ltr[2], 1, info->a[6]); s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]); s->tr[4] = ltr[4] >> 11; s->tr[5] = ltr[5] >> 11; s->tr[6] = muldiv64(ltr[6], 1, info->a[6]); s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);#else /* This version assumes touchscreen X & Y axis are parallel or * perpendicular to LCD's X & Y axis in some way. */ if (abs(info->a[0]) > abs(info->a[1])) { s->tr[0] = 0; s->tr[1] = -info->a[6] * info->x; s->tr[2] = info->a[0]; s->tr[3] = -info->a[2] / info->a[0]; s->tr[4] = info->a[6] * info->y; s->tr[5] = 0; s->tr[6] = info->a[4]; s->tr[7] = -info->a[5] / info->a[4]; } else { s->tr[0] = info->a[6] * info->y; s->tr[1] = 0; s->tr[2] = info->a[1]; s->tr[3] = -info->a[2] / info->a[1]; s->tr[4] = 0; s->tr[5] = -info->a[6] * info->x; s->tr[6] = info->a[3]; s->tr[7] = -info->a[5] / info->a[3]; } s->tr[0] >>= 11; s->tr[1] >>= 11; s->tr[3] <<= 4; s->tr[4] >>= 11; s->tr[5] >>= 11; s->tr[7] <<= 4;#endif}void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down){ struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; if (down) s->kb.down |= 1 << key; else s->kb.down &= ~(1 << key); if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) { s->kb.intr = 1; qemu_irq_lower(s->kbint); } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) && !(s->kb.mode & 1)) { s->kb.intr = 0; qemu_irq_raise(s->kbint); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -