📄 tsc210x.c.svn-base
字号:
case 0x07: /* AUX1 */ case 0x08: /* AUX2 */ case 0x09: /* TEMP1 */ case 0x0a: /* TEMP2 */ return; default:#ifdef TSC_VERBOSE fprintf(stderr, "tsc2102_data_register_write: " "no such register: 0x%02x\n", reg);#endif }}static void tsc2102_control_register_write( struct tsc210x_state_s *s, int reg, uint16_t value){ switch (reg) { case 0x00: /* TSC ADC */ s->host_mode = value >> 15; s->enabled = !(value & 0x4000); if (s->busy && !s->enabled) qemu_del_timer(s->timer); s->busy &= s->enabled; s->nextfunction = (value >> 10) & 0xf; s->nextprecision = (value >> 8) & 3; s->filter = value & 0xff; return; case 0x01: /* Status */ s->pin_func = value >> 14; return; case 0x03: /* Reference */ s->ref = value & 0x1f; return; case 0x04: /* Reset */ if (value == 0xbb00) { if (s->busy) qemu_del_timer(s->timer); tsc210x_reset(s);#ifdef TSC_VERBOSE } else { fprintf(stderr, "tsc2102_control_register_write: " "wrong value written into RESET\n");#endif } return; case 0x05: /* Configuration */ s->timing = value & 0x3f;#ifdef TSC_VERBOSE if (value & ~0x3f) fprintf(stderr, "tsc2102_control_register_write: " "wrong value written into CONFIG\n");#endif return; default:#ifdef TSC_VERBOSE fprintf(stderr, "tsc2102_control_register_write: " "no such register: 0x%02x\n", reg);#endif }}static void tsc2102_audio_register_write( struct tsc210x_state_s *s, int reg, uint16_t value){ switch (reg) { case 0x00: /* Audio Control 1 */ s->audio_ctrl1 = value & 0x0f3f;#ifdef TSC_VERBOSE if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7))) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Audio 1\n");#endif tsc2102_audio_rate_update(s); if (s->audio) tsc2102_audio_output_update(s); return; case 0x01:#ifdef TSC_VERBOSE if (value != 0xff00) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into reg 0x01\n");#endif return; case 0x02: /* DAC Volume Control */ s->volume = value; s->volume_change = qemu_get_clock(vm_clock); return; case 0x03:#ifdef TSC_VERBOSE if (value != 0x8b00) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into reg 0x03\n");#endif return; case 0x04: /* Audio Control 2 */ s->audio_ctrl2 = value & 0xf7f2;#ifdef TSC_VERBOSE if (value & ~0xf7fd) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Audio 2\n");#endif return; case 0x05: /* Stereo DAC Power Control */ if ((value & ~s->dac_power) & (1 << 10)) s->powerdown = qemu_get_clock(vm_clock); s->dac_power = value & 0x9543;#ifdef TSC_VERBOSE if ((value & ~0x9543) != 0x2aa0) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Power\n");#endif tsc2102_audio_rate_update(s); if (s->audio) tsc2102_audio_output_update(s); return; case 0x06: /* Audio Control 3 */ s->audio_ctrl3 &= 0x00c0; s->audio_ctrl3 |= value & 0xf800;#ifdef TSC_VERBOSE if (value & ~0xf8c7) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Audio 3\n");#endif if (s->audio) tsc2102_audio_output_update(s); return; case 0x07: /* LCH_BASS_BOOST_N0 */ case 0x08: /* LCH_BASS_BOOST_N1 */ case 0x09: /* LCH_BASS_BOOST_N2 */ case 0x0a: /* LCH_BASS_BOOST_N3 */ case 0x0b: /* LCH_BASS_BOOST_N4 */ case 0x0c: /* LCH_BASS_BOOST_N5 */ case 0x0d: /* LCH_BASS_BOOST_D1 */ case 0x0e: /* LCH_BASS_BOOST_D2 */ case 0x0f: /* LCH_BASS_BOOST_D4 */ case 0x10: /* LCH_BASS_BOOST_D5 */ case 0x11: /* RCH_BASS_BOOST_N0 */ case 0x12: /* RCH_BASS_BOOST_N1 */ case 0x13: /* RCH_BASS_BOOST_N2 */ case 0x14: /* RCH_BASS_BOOST_N3 */ case 0x15: /* RCH_BASS_BOOST_N4 */ case 0x16: /* RCH_BASS_BOOST_N5 */ case 0x17: /* RCH_BASS_BOOST_D1 */ case 0x18: /* RCH_BASS_BOOST_D2 */ case 0x19: /* RCH_BASS_BOOST_D4 */ case 0x1a: /* RCH_BASS_BOOST_D5 */ s->filter_data[reg - 0x07] = value; return; case 0x1b: /* PLL Programmability 1 */ s->pll[0] = value & 0xfffc;#ifdef TSC_VERBOSE if (value & ~0xfffc) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into PLL 1\n");#endif return; case 0x1c: /* PLL Programmability 2 */ s->pll[1] = value & 0xfffc;#ifdef TSC_VERBOSE if (value & ~0xfffc) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into PLL 2\n");#endif return; case 0x1d: /* Audio Control 4 */ s->softstep = !(value & 0x4000);#ifdef TSC_VERBOSE if (value & ~0x4000) fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Audio 4\n");#endif return; default:#ifdef TSC_VERBOSE fprintf(stderr, "tsc2102_audio_register_write: " "no such register: 0x%02x\n", reg);#endif }}/* This handles most of the chip logic. */static void tsc210x_pin_update(struct tsc210x_state_s *s){ int64_t expires; int pin_state; switch (s->pin_func) { case 0: pin_state = s->pressure; break; case 1: pin_state = !!s->dav; break; case 2: default: pin_state = s->pressure && !s->dav; } if (!s->enabled) pin_state = 0; if (pin_state != s->irq) { s->irq = pin_state; qemu_set_irq(s->pint, !s->irq); } switch (s->nextfunction) { case TSC_MODE_XY_SCAN: case TSC_MODE_XYZ_SCAN: if (!s->pressure) return; break; case TSC_MODE_X: case TSC_MODE_Y: case TSC_MODE_Z: if (!s->pressure) return; /* Fall through */ case TSC_MODE_BAT1: case TSC_MODE_BAT2: case TSC_MODE_AUX: case TSC_MODE_TEMP1: case TSC_MODE_TEMP2: if (s->dav) s->enabled = 0; break; case TSC_MODE_AUX_SCAN: case TSC_MODE_PORT_SCAN: break; case TSC_MODE_NO_SCAN: case TSC_MODE_XX_DRV: case TSC_MODE_YY_DRV: case TSC_MODE_YX_DRV: default: return; } if (!s->enabled || s->busy) return; s->busy = 1; s->precision = s->nextprecision; s->function = s->nextfunction; expires = qemu_get_clock(vm_clock) + (ticks_per_sec >> 10); qemu_mod_timer(s->timer, expires);}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); 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; }}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);}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); 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->name = "tsc2102"; s->audio = audio; 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 i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip){ struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; return &s->codec;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -