123 lines
4.2 KiB
C
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();
|
|
}
|