Files
qemu-ios/contrib/ipod-emu/tests/test-uart.c
T

123 lines
4.2 KiB
C

/* Reset UART : registres, FIFO, IRQ et reconnexion du relais série. */
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "sysemu/cpus.h"
#include "sysemu/sysemu.h"
#include <sys/socket.h>
#include <sys/un.h>
#include "hw/arm/ipod_touch_uart.c"
static void irq_changed(void *opaque, int n, int level)
{
*(int *)opaque = level;
}
static void test_register_reset(void)
{
IPodTouchUARTState *s = IPOD_TOUCH_UART(object_new(TYPE_IPOD_TOUCH_UART));
int level = 0;
qemu_irq irq = qemu_allocate_irq(irq_changed, &level, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(s), 0, irq);
uint8_t bytes[] = { 0x7e, 0xff, 0x03, 0x7d };
uart_write(s, ULCON, 3, 4);
uart_write(s, UCON, UCON_RX_INT | UCON_RXTO_INT | UCON_TX_INT, 4);
uart_write(s, UMCON, 1, 4);
uart_write(s, UBRDIV, 100, 4);
uart_receive(s, bytes, sizeof bytes);
g_assert_cmpint(level, ==, 1);
g_assert_cmpuint(uart_read(s, UFSTAT, 4), ==, sizeof bytes);
device_cold_reset(DEVICE(s));
g_assert_cmpint(level, ==, 0);
g_assert_cmpuint(uart_read(s, UTRSTAT, 4), ==,
UTRSTAT_TXBUF_EMPTY | UTRSTAT_TX_EMPTY);
g_assert_cmpuint(uart_read(s, UFSTAT, 4), ==, 0);
g_assert_cmpuint(uart_read(s, ULCON, 4), ==, 0);
g_assert_cmpuint(uart_read(s, UCON, 4), ==, 0);
g_assert_cmpuint(uart_read(s, UMCON, 4), ==, 0);
g_assert_cmpuint(uart_read(s, UBRDIV, 4), ==, 0);
object_unref(OBJECT(s));
qemu_free_irq(irq);
}
static void wait_open(IPodTouchUARTState *s)
{
int64_t deadline = g_get_monotonic_time() + 5 * G_USEC_PER_SEC;
while (!qemu_chr_fe_backend_open(&s->chr)) {
g_assert_cmpint(g_get_monotonic_time(), <, deadline);
main_loop_wait(true);
g_usleep(1000);
}
}
static int connect_client(const char *path)
{
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
g_strlcpy(addr.sun_path, path, sizeof addr.sun_path);
g_assert_cmpint(fd, >=, 0);
struct timeval limit = { .tv_sec = 5 };
g_assert_cmpint(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &limit, sizeof limit), ==, 0);
g_assert_cmpint(connect(fd, (struct sockaddr *)&addr, sizeof addr), ==, 0);
return fd;
}
static void test_socket_reconnect(void)
{
char *dir = g_dir_make_tmp("ipod-uart-XXXXXX", NULL);
g_assert_nonnull(dir);
char *path = g_build_filename(dir, "uart.sock", NULL);
char *spec = g_strdup_printf("unix:%s,server=on,wait=off", path);
Chardev *chr = qemu_chr_new("uart-test", spec, NULL);
g_assert_nonnull(chr);
IPodTouchUARTState *s = IPOD_TOUCH_UART(object_new(TYPE_IPOD_TOUCH_UART));
qemu_chr_fe_init(&s->chr, chr, &error_abort);
uart_realize(DEVICE(s), &error_abort);
for (int cycle = 0; cycle < 3; cycle++) {
int fd = connect_client(path);
wait_open(s);
uint8_t incoming = 0x41 + cycle;
g_assert_cmpint(write(fd, &incoming, 1), ==, 1);
int64_t deadline = g_get_monotonic_time() + 5 * G_USEC_PER_SEC;
while (!s->rx_count) {
g_assert_cmpint(g_get_monotonic_time(), <, deadline);
main_loop_wait(true);
g_usleep(1000);
}
g_assert_cmpuint(uart_read(s, URXH, 1), ==, incoming);
uart_write(s, UTXH, 0x7e, 1);
uint8_t b = 0;
g_assert_cmpint(read(fd, &b, 1), ==, 1);
g_assert_cmpuint(b, ==, 0x7e);
device_cold_reset(DEVICE(s));
/* Le relais voit la fin du lien et peut renégocier avec le nouvel iOS. */
g_assert_false(qemu_chr_fe_backend_open(&s->chr));
g_assert_cmpint(read(fd, &b, 1), ==, 0);
close(fd);
}
qemu_chr_fe_deinit(&s->chr, false);
object_unref(OBJECT(s));
object_unparent(OBJECT(chr));
unlink(path);
rmdir(dir);
g_free(spec);
g_free(path);
g_free(dir);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_chardev_opts);
qemu_init_main_loop(&error_abort);
qemu_init_cpu_loop();
qemu_mutex_lock_iothread();
g_test_add_func("/ipod-uart/register-reset", test_register_reset);
g_test_add_func("/ipod-uart/socket-reconnect", test_socket_reconnect);
return g_test_run();
}