201 lines
7.7 KiB
C
201 lines
7.7 KiB
C
/* Régressions du protocole tactile : commandes invalides et trames concurrentes. */
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/main-loop.h"
|
|
#include "sysemu/cpus.h"
|
|
#include "hw/arm/ipod_touch_multitouch.c"
|
|
#include "hw/arm/ipod_touch_gpio.c"
|
|
#include "hw/arm/ipod_touch_sysic.c"
|
|
#include "hw/arm/ipod_touch_spi.c"
|
|
|
|
static IPodTouchMultitouchState *new_sensor(void)
|
|
{
|
|
IPodTouchMultitouchState *s = IPOD_TOUCH_MULTITOUCH(
|
|
object_new(TYPE_IPOD_TOUCH_MULTITOUCH));
|
|
ipod_touch_multitouch_realize(SSI_PERIPHERAL(s), &error_abort);
|
|
return s;
|
|
}
|
|
|
|
static void destroy_sensor(IPodTouchMultitouchState *s)
|
|
{
|
|
finish_transfer(s);
|
|
timer_free(s->touch_timer);
|
|
timer_free(s->touch_end_timer);
|
|
g_free(s->next_frame);
|
|
g_free(s->read_frame);
|
|
object_unref(OBJECT(s));
|
|
}
|
|
|
|
static uint8_t transfer(IPodTouchMultitouchState *s, uint8_t byte)
|
|
{
|
|
return ipod_touch_multitouch_transfer(SSI_PERIPHERAL(s), byte);
|
|
}
|
|
|
|
static void test_unknown(void)
|
|
{
|
|
IPodTouchMultitouchState *s = new_sensor();
|
|
for (int i = 0; i < 10000; i++) {
|
|
g_assert_cmpuint(transfer(s, 0xab), ==, 0xff);
|
|
g_assert_cmpuint(s->cur_cmd, ==, 0);
|
|
g_assert_null(s->in_buffer);
|
|
}
|
|
uint8_t out[16];
|
|
out[0] = transfer(s, MT_CMD_GET_INTERFACE_VERSION);
|
|
for (int i = 1; i < 16; i++) out[i] = transfer(s, 0);
|
|
g_assert_cmpuint(out[2], ==, MT_INTERFACE_VERSION);
|
|
destroy_sensor(s);
|
|
}
|
|
|
|
static void test_snapshot(void)
|
|
{
|
|
IPodTouchMultitouchState *s = new_sensor();
|
|
MTFrame expected = *s->next_frame;
|
|
uint8_t out[sizeof(MTFrame)];
|
|
out[0] = transfer(s, MT_CMD_FRAME_READ);
|
|
for (int i = 1; i < 16; i++) out[i] = transfer(s, 0);
|
|
g_free(s->next_frame);
|
|
s->next_frame = get_frame(s, MT_EVENT_TOUCH_START, .4, .6,
|
|
100, 660, 580, 150);
|
|
g_assert_cmpuint(s->cur_cmd, ==, 0);
|
|
out[16] = transfer(s, 0xeb);
|
|
out[17] = transfer(s, 0);
|
|
out[18] = transfer(s, 1);
|
|
for (size_t i = 19; i < sizeof out; i++) out[i] = transfer(s, 0);
|
|
expected.frame_packet.unused1 = expected.frame_length.length1;
|
|
expected.frame_packet.checksum_pad = -(expected.frame_packet.cmd +
|
|
expected.frame_packet.unused1 + expected.frame_packet.length1 +
|
|
expected.frame_packet.length2);
|
|
g_assert_cmpmem(out, sizeof out, &expected, sizeof expected);
|
|
g_assert_cmpuint(s->next_frame->finger_data.event, ==, MT_EVENT_TOUCH_START);
|
|
destroy_sensor(s);
|
|
}
|
|
|
|
static void test_reports(void)
|
|
{
|
|
IPodTouchMultitouchState *s = new_sensor();
|
|
uint8_t out[16];
|
|
for (int cmd = MT_CMD_GET_REPORT_INFO; cmd <= MT_CMD_SHORT_CONTROL_READ; cmd += 3) {
|
|
out[0] = transfer(s, cmd);
|
|
out[1] = transfer(s, 0xff);
|
|
for (int i = 2; i < 16; i++) out[i] = transfer(s, 0);
|
|
g_assert_cmpuint(out[2], ==, 1);
|
|
unsigned sum = 0;
|
|
for (int i = 0; i < 14; i++) sum += out[i];
|
|
g_assert_cmpuint(lduw_le_p(out + 14), ==, sum);
|
|
}
|
|
transfer(s, MT_CMD_SHORT_CONTROL_READ);
|
|
transfer(s, MT_REPORT_SENSOR_DIMENSIONS);
|
|
for (int i = 2; i < 16; i++) out[i] = transfer(s, 0);
|
|
g_assert_cmpuint(ldl_le_p(out + 3), ==, 5000);
|
|
g_assert_cmpuint(ldl_le_p(out + 7), ==, 7500);
|
|
destroy_sensor(s);
|
|
}
|
|
|
|
static void test_spi_abort(void)
|
|
{
|
|
IPodTouchSPIState *spi = IPOD_TOUCH_SPI(object_new(TYPE_IPOD_TOUCH_SPI));
|
|
DEVICE(spi)->id = g_strdup("spi-test");
|
|
set_spi_base(4);
|
|
ipod_touch_spi_realize(DEVICE(spi), &error_abort);
|
|
ipod_touch_spi_write(spi, R_TXCNT, 2, 4);
|
|
ipod_touch_spi_write(spi, R_RXCNT, 2, 4);
|
|
ipod_touch_spi_write(spi, R_TXDATA, MT_CMD_FRAME_READ, 4);
|
|
ipod_touch_spi_write(spi, R_TXDATA, 2, 4);
|
|
ipod_touch_spi_write(spi, R_CTRL, R_CTRL_RUN, 4);
|
|
g_assert_cmpuint(spi->mt->in_buffer_ind, ==, 2);
|
|
ipod_touch_spi_write(spi, R_CTRL, R_CTRL_TX_RESET | R_CTRL_RX_RESET, 4);
|
|
g_assert_cmpuint(spi->mt->cur_cmd, ==, 0);
|
|
g_assert_null(spi->mt->in_buffer);
|
|
uint8_t response[16];
|
|
response[0] = transfer(spi->mt, MT_CMD_GET_INTERFACE_VERSION);
|
|
for (int i = 1; i < 16; i++) response[i] = transfer(spi->mt, 0);
|
|
g_assert_cmpuint(response[2], ==, MT_INTERFACE_VERSION);
|
|
timer_free(spi->mt->touch_timer);
|
|
timer_free(spi->mt->touch_end_timer);
|
|
g_free(spi->mt->next_frame);
|
|
fifo8_destroy(&spi->tx_fifo);
|
|
fifo8_destroy(&spi->rx_fifo);
|
|
object_unref(OBJECT(spi));
|
|
}
|
|
|
|
static void test_hbpp(void)
|
|
{
|
|
IPodTouchMultitouchState *s = new_sensor();
|
|
uint8_t bad[10] = {MT_CMD_HBPP_DATA_PACKET, 0, 0, 4};
|
|
for (int i = 0; i < 10; i++) transfer(s, bad[i]);
|
|
g_assert_cmpuint(s->cur_cmd, ==, 0);
|
|
uint8_t good[10] = {MT_CMD_HBPP_DATA_PACKET, 0, 0, 4, 0, 0, 0, 0, 0, 4};
|
|
for (int i = 0; i < 10; i++) transfer(s, good[i]);
|
|
for (int i = 1; i < 21; i++) transfer(s, 0);
|
|
g_assert_cmpuint(s->cur_cmd, ==, 0);
|
|
destroy_sensor(s);
|
|
}
|
|
|
|
static void test_velocity(void)
|
|
{
|
|
IPodTouchMultitouchState *s = new_sensor();
|
|
MTFrame *f = get_frame(s, MT_EVENT_TOUCH_MOVED, .4, .6, 1, 1, 1, 1);
|
|
g_free(f);
|
|
f = get_frame(s, MT_EVENT_TOUCH_MOVED, .4, .7, 1, 1, 1, 1);
|
|
g_assert_cmpint(f->finger_data.velX, ==, 0);
|
|
g_assert_cmpint(f->finger_data.velY, >, 0);
|
|
g_free(f);
|
|
f = get_frame(s, MT_EVENT_TOUCH_MOVED, .4, .7, 1, 1, 1, 1);
|
|
g_assert_cmpint(f->finger_data.velX, ==, 0);
|
|
g_assert_cmpint(f->finger_data.velY, ==, 0);
|
|
g_free(f);
|
|
destroy_sensor(s);
|
|
}
|
|
|
|
static void test_buttons(void)
|
|
{
|
|
IPodTouchGPIOState *s = IPOD_TOUCH_GPIO(object_new(TYPE_IPOD_TOUCH_GPIO));
|
|
g_assert_cmpuint(GPIO2PAD(GPIO_BUTTON_HOME), <, NUM_GPIO_PADS);
|
|
gpio_set_on(s->gpio_state, GPIO_BUTTON_HOME);
|
|
gpio_set_on(s->gpio_state, GPIO_BUTTON_POWER);
|
|
g_assert_true(gpio_is_on(s->gpio_state, GPIO_BUTTON_HOME));
|
|
g_assert_true(gpio_is_on(s->gpio_state, GPIO_BUTTON_POWER));
|
|
gpio_set_off(s->gpio_state, GPIO_BUTTON_HOME);
|
|
g_assert_true(gpio_is_off(s->gpio_state, GPIO_BUTTON_HOME));
|
|
g_assert_true(gpio_is_on(s->gpio_state, GPIO_BUTTON_POWER));
|
|
object_unref(OBJECT(s));
|
|
}
|
|
|
|
static void test_gpio_ranges(void)
|
|
{
|
|
IPodTouchSYSICState *s = IPOD_TOUCH_SYSIC(object_new(TYPE_IPOD_TOUCH_SYSIC));
|
|
uint32_t arrays[4][GPIO_NUMINTGROUPS];
|
|
s->gpio_int_level[0] = 0x1234;
|
|
memcpy(arrays[0], s->gpio_int_level, sizeof arrays[0]);
|
|
memcpy(arrays[1], s->gpio_int_status, sizeof arrays[1]);
|
|
memcpy(arrays[2], s->gpio_int_enabled, sizeof arrays[2]);
|
|
memcpy(arrays[3], s->gpio_int_type, sizeof arrays[3]);
|
|
/* Les quatre trous entre groupes ne doivent pas accéder au tableau suivant. */
|
|
for (int addr = GPIO_INTLEVEL; addr <= GPIO_INTTYPE; addr += 0x20) {
|
|
ipod_touch_sysic_write(s, addr + GPIO_NUMINTGROUPS * 4, 0xffffffff, 4);
|
|
g_assert_cmpuint(ipod_touch_sysic_read(s, addr + GPIO_NUMINTGROUPS * 4, 4), ==, 0);
|
|
}
|
|
g_assert_cmpmem(arrays[0], sizeof arrays[0], s->gpio_int_level, sizeof arrays[0]);
|
|
g_assert_cmpmem(arrays[1], sizeof arrays[1], s->gpio_int_status, sizeof arrays[1]);
|
|
g_assert_cmpmem(arrays[2], sizeof arrays[2], s->gpio_int_enabled, sizeof arrays[2]);
|
|
g_assert_cmpmem(arrays[3], sizeof arrays[3], s->gpio_int_type, sizeof arrays[3]);
|
|
object_unref(OBJECT(s));
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
g_test_init(&argc, &argv, NULL);
|
|
module_call_init(MODULE_INIT_QOM);
|
|
qemu_init_main_loop(&error_abort);
|
|
qemu_init_cpu_loop();
|
|
qemu_mutex_lock_iothread();
|
|
g_test_add_func("/ipod-multitouch/unknown", test_unknown);
|
|
g_test_add_func("/ipod-multitouch/snapshot", test_snapshot);
|
|
g_test_add_func("/ipod-multitouch/hbpp", test_hbpp);
|
|
g_test_add_func("/ipod-multitouch/spi-abort", test_spi_abort);
|
|
g_test_add_func("/ipod-multitouch/reports", test_reports);
|
|
g_test_add_func("/ipod-multitouch/velocity", test_velocity);
|
|
g_test_add_func("/ipod-input/buttons", test_buttons);
|
|
g_test_add_func("/ipod-input/gpio-ranges", test_gpio_ranges);
|
|
return g_test_run();
|
|
}
|