Read about our upcoming Code of Conduct on this issue

Commit fb6fe7f4 authored by Alex's avatar Alex
Browse files

Merged in edmac (pull request #811)

EDMAC module + fixes

--HG--
branch : unified
......@@ -9,6 +9,7 @@ top_dir = "../"
force_used = [
"SetASIFMode",
"_audio_ic_write_bulk",
"AbortEDmac",
]
force_unused = [
"vram_get_number", # old way of accessing VRAM (5D2 only)
......@@ -71,6 +72,7 @@ def cleanup_stub(inp_file, out_file):
lines = open(inp_file).readlines()
if out_file: out_file = open(out_file, "w")
else: out_file = sys.stdout
# for each line
for l in lines:
......@@ -85,17 +87,25 @@ def cleanup_stub(inp_file, out_file):
if not check_used(name):
print "%s: unused" % name
if "???," not in l:
if out_file:
print >> out_file, comment_out(l)
print >> out_file, comment_out(l)
continue
elif name in force_used and l.strip().startswith("///"):
# commented out? uncomment and the address looks valid
addr = m.groups()[1]
addr = addr.replace("RAM_OFFSET", "");
addr = addr.strip(" -");
try:
addr = int(addr, 16)
l = l.lstrip('/ ')
except:
print "%s: invalid address %s" % (name, addr)
if out_file:
print >> out_file, l
print >> out_file, l
if out_file:
if out_file != sys.stdout:
out_file.close()
check_used("FIO_ReadFile")
#check_used("CreateDialogBox")
inputs = sys.argv[1:]
......
......@@ -8,6 +8,39 @@ extern WEAK_FUNC(ret_0) void* edmac_copy_rectangle_adv(void* dst, void* src, int
#define HAS_DMA_MEMCPY ((void*)&dma_memcpy != (void*)&ret_0)
#define HAS_EDMAC_MEMCPY ((void*)&edmac_memcpy != (void*)&ret_0)
static void mem_benchmark_fill(uint32_t * src, uint32_t * dst, int size)
{
for (int i = 0; i < size/4; i++)
{
src[i] = rand();
}
memset(dst, 0, size);
}
static void mem_benchmark_check(void* src, void* dst, int size, int x, int y)
{
sync_caches();
int color_fg = COLOR_WHITE;
char * msg = "OK";
if (memcmp(src, dst, size) != 0)
{
msg = "ERR!";
color_fg = COLOR_RED;
/* save the source and destination buffers, for debugging */
dump_seg(src, size, "ML/LOGS/benchsrc.bin");
dump_seg(dst, size, "ML/LOGS/benchdst.bin");
}
bmp_printf(
FONT(FONT_MONO_20, color_fg, COLOR_BLACK) | FONT_ALIGN_RIGHT,
x, y, msg
);
}
typedef void (*mem_bench_fun)(
int arg0,
int arg1,
......@@ -15,7 +48,7 @@ typedef void (*mem_bench_fun)(
int arg3
);
static void mem_benchmark_run(char* msg, int* y, int bufsize, mem_bench_fun bench_fun, int arg0, int arg1, int arg2, int arg3)
static void mem_benchmark_run(char* msg, int* y, int bufsize, mem_bench_fun bench_fun, int arg0, int arg1, int arg2, int arg3, int is_memcpy)
{
bmp_fill(COLOR_BLACK, 0, 0, 720, font_large.height);
bmp_printf(FONT_LARGE, 0, 0, "%s", msg);
......@@ -41,10 +74,11 @@ static void mem_benchmark_run(char* msg, int* y, int bufsize, mem_bench_fun benc
msleep(500);
display_off();
}
msleep(100);
msleep(200);
int times = 0;
int t0 = get_ms_clock_value();
int t0m = get_ms_clock_value();
int64_t t0 = get_us_clock_value();
for (int i = 0; i < INT_MAX; i++)
{
if (i%2) info_led_off(); else info_led_on();
......@@ -52,19 +86,19 @@ static void mem_benchmark_run(char* msg, int* y, int bufsize, mem_bench_fun benc
bench_fun(arg0, arg1, arg2, arg3);
/* run the benchmark for roughly 1 second */
if (get_ms_clock_value_fast() - t0 > 1000)
if (get_ms_clock_value_fast() - t0m > 1000)
{
times = i + 1;
break;
}
}
int t1 = get_ms_clock_value();
int dt = t1 - t0;
int64_t t1 = get_us_clock_value();
int64_t dt = t1 - t0;
info_led_off();
/* units: KB/s */
int speed = bufsize * times / dt;
int speed = (int64_t) bufsize * times * 1000000ull / dt / 1024;
/* transform in MB/s x100 */
speeds[display] = speed * 100 / 1024;
......@@ -72,13 +106,30 @@ static void mem_benchmark_run(char* msg, int* y, int bufsize, mem_bench_fun benc
if (speeds[0])
{
bmp_printf(FONT_MONO_20, 0, *y += 20, "%s :%4d.%02d MB/s; %4d.%02d MB/s disp off", msg, speeds[1]/100, speeds[1]%100, speeds[0]/100, speeds[0]%100);
bmp_printf(FONT_MONO_20, 0, 100, "Test function: Display on: Display off: ");
bmp_printf(FONT_MONO_20, 0, *y += 20, "%s %4d.%02d MB/s %4d.%02d MB/s ", msg, speeds[1]/100, speeds[1]%100, speeds[0]/100, speeds[0]%100);
}
else
{
bmp_printf(FONT_MONO_20, 0, *y += 20, "%s :%4d.%02d MB/s; (test skipped) ", msg, speeds[1]/100, speeds[1]%100);
bmp_printf(FONT_MONO_20, 0, *y += 20, "%s %4d.%02d MB/s (test skipped) ", msg, speeds[1]/100, speeds[1]%100);
}
msleep(1000);
display_on();
if (is_memcpy)
{
/* perform an extra call, just for checking whether the copying is done correctly */
/* assume memcpy-like syntax: (src, dst, size) */
info_led_on();
bmp_printf(FONT_LARGE, 0, 0, "%s (verifying) ", msg);
bmp_printf(FONT_MONO_20 | FONT_ALIGN_RIGHT, 720, *y, SYM_DOTS);
mem_benchmark_fill((void*)arg1, (void*)arg0, arg2);
bench_fun(arg0, arg1, arg2, arg3);
mem_benchmark_check((void*)arg1, (void*)arg0, arg2, 720, *y);
info_led_off();
}
msleep(200);
}
static void mem_test_bmp_fill(int arg0, int arg1, int arg2, int arg3)
......@@ -156,42 +207,42 @@ static void mem_benchmark_task()
goto cleanup;
}
int y = 80;
int y = 100;
#if 0 // need to hack the source code to run this benchmark
extern int defish_ind;
defish_draw_lv_color();
void defish_draw_lv_color_loop(uint64_t* src_buf, uint64_t* dst_buf, int* ind);
if (defish_ind)
mem_benchmark_run("defish_draw_lv_color", &y, 720*os.y_ex, (mem_bench_fun)defish_draw_lv_color_loop, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), defish_ind, 0);
mem_benchmark_run("defish_draw_lv_color", &y, 720*os.y_ex, (mem_bench_fun)defish_draw_lv_color_loop, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), defish_ind, 0, 0);
#endif
mem_benchmark_run("memcpy cacheable ", &y, bufsize, (mem_bench_fun)memcpy, (intptr_t)CACHEABLE(buf1), (intptr_t)CACHEABLE(buf2), bufsize, 0);
mem_benchmark_run("memcpy uncacheable ", &y, bufsize, (mem_bench_fun)memcpy, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0);
mem_benchmark_run("memcpy64 cacheable ", &y, bufsize, (mem_bench_fun)memcpy64, (intptr_t)CACHEABLE(buf1), (intptr_t)CACHEABLE(buf2), bufsize, 0);
mem_benchmark_run("memcpy64 uncacheable", &y, bufsize, (mem_bench_fun)memcpy64, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0);
mem_benchmark_run("memcpy cacheable ", &y, bufsize, (mem_bench_fun)memcpy, (intptr_t)CACHEABLE(buf1), (intptr_t)CACHEABLE(buf2), bufsize, 0, 1);
mem_benchmark_run("memcpy uncacheable ", &y, bufsize, (mem_bench_fun)memcpy, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0, 1);
mem_benchmark_run("memcpy64 cacheable ", &y, bufsize, (mem_bench_fun)memcpy64, (intptr_t)CACHEABLE(buf1), (intptr_t)CACHEABLE(buf2), bufsize, 0, 1);
mem_benchmark_run("memcpy64 uncacheable", &y, bufsize, (mem_bench_fun)memcpy64, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0, 1);
if (HAS_DMA_MEMCPY)
{
mem_benchmark_run("dma_memcpy cacheable", &y, bufsize, (mem_bench_fun)dma_memcpy, (intptr_t)CACHEABLE(buf1), (intptr_t)CACHEABLE(buf2), bufsize, 0);
mem_benchmark_run("dma_memcpy uncacheab", &y, bufsize, (mem_bench_fun)dma_memcpy, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0);
mem_benchmark_run("dma_memcpy cacheable", &y, bufsize, (mem_bench_fun)dma_memcpy, (intptr_t)CACHEABLE(buf1), (intptr_t)CACHEABLE(buf2), bufsize, 0, 1);
mem_benchmark_run("dma_memcpy uncacheab", &y, bufsize, (mem_bench_fun)dma_memcpy, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0, 1);
}
if (HAS_EDMAC_MEMCPY)
{
mem_benchmark_run("edmac_memcpy ", &y, bufsize, (mem_bench_fun)edmac_memcpy, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0);
mem_benchmark_run("edmac_copy_rectangle", &y, 720*480, (mem_bench_fun)mem_test_edmac_copy_rectangle, 0, 0, 0, 0);
mem_benchmark_run("edmac_memcpy ", &y, bufsize, (mem_bench_fun)edmac_memcpy, (intptr_t)UNCACHEABLE(buf1), (intptr_t)UNCACHEABLE(buf2), bufsize, 0, 1);
mem_benchmark_run("edmac_copy_rectangle", &y, 720*480, (mem_bench_fun)mem_test_edmac_copy_rectangle, 0, 0, 0, 0, 0);
}
mem_benchmark_run("memset cacheable ", &y, bufsize, (mem_bench_fun)memset, (intptr_t)CACHEABLE(buf1), 0, bufsize, 0);
mem_benchmark_run("memset uncacheable ", &y, bufsize, (mem_bench_fun)memset, (intptr_t)UNCACHEABLE(buf1), 0, bufsize, 0);
mem_benchmark_run("memset64 cacheable ", &y, bufsize, (mem_bench_fun)memset64, (intptr_t)CACHEABLE(buf1), 0, bufsize, 0);
mem_benchmark_run("memset64 uncacheable", &y, bufsize, (mem_bench_fun)memset64, (intptr_t)UNCACHEABLE(buf1), 0, bufsize, 0);
mem_benchmark_run("read32 cacheable ", &y, bufsize, (mem_bench_fun)mem_test_read32, (intptr_t)CACHEABLE(buf1), bufsize, 0, 0);
mem_benchmark_run("read32 uncacheable ", &y, bufsize, (mem_bench_fun)mem_test_read32, (intptr_t)UNCACHEABLE(buf1), bufsize, 0, 0);
mem_benchmark_run("read64 cacheable ", &y, bufsize, (mem_bench_fun)mem_test_read64, (intptr_t)CACHEABLE(buf1), bufsize, 0, 0);
mem_benchmark_run("read64 uncacheable ", &y, bufsize, (mem_bench_fun)mem_test_read64, (intptr_t)UNCACHEABLE(buf1), bufsize, 0, 0);
mem_benchmark_run("bmp_fill to idle buf", &y, 720*480, (mem_bench_fun)mem_test_bmp_fill, 0, 0, 720, 480);
mem_benchmark_run("memset cacheable ", &y, bufsize, (mem_bench_fun)memset, (intptr_t)CACHEABLE(buf1), 0, bufsize, 0, 0);
mem_benchmark_run("memset uncacheable ", &y, bufsize, (mem_bench_fun)memset, (intptr_t)UNCACHEABLE(buf1), 0, bufsize, 0, 0);
mem_benchmark_run("memset64 cacheable ", &y, bufsize, (mem_bench_fun)memset64, (intptr_t)CACHEABLE(buf1), 0, bufsize, 0, 0);
mem_benchmark_run("memset64 uncacheable", &y, bufsize, (mem_bench_fun)memset64, (intptr_t)UNCACHEABLE(buf1), 0, bufsize, 0, 0);
mem_benchmark_run("read32 cacheable ", &y, bufsize, (mem_bench_fun)mem_test_read32, (intptr_t)CACHEABLE(buf1), bufsize, 0, 0, 0);
mem_benchmark_run("read32 uncacheable ", &y, bufsize, (mem_bench_fun)mem_test_read32, (intptr_t)UNCACHEABLE(buf1), bufsize, 0, 0, 0);
mem_benchmark_run("read64 cacheable ", &y, bufsize, (mem_bench_fun)mem_test_read64, (intptr_t)CACHEABLE(buf1), bufsize, 0, 0, 0);
mem_benchmark_run("read64 uncacheable ", &y, bufsize, (mem_bench_fun)mem_test_read64, (intptr_t)UNCACHEABLE(buf1), bufsize, 0, 0, 0);
mem_benchmark_run("bmp_fill to idle buf", &y, 720*480, (mem_bench_fun)mem_test_bmp_fill, 0, 0, 720, 480, 0);
bmp_fill(COLOR_BLACK, 0, 0, 720, font_large.height);
bmp_printf(FONT_LARGE, 0, 0, "Benchmark complete.");
......
# define the module name - make sure name is max 8 characters
MODULE_NAME=edmac
MODULE_OBJS=edmac.o edmac_util.o edmac_test.o md5.o
# include modules environment
include ../Makefile.modules
# fixme: cleaner way to localize symbols?
edmac.sym: edmac.mo
$(call build,STRIP,$(READELF) -sW $< | grep GLOBAL | grep -v UND | grep -v COM | grep -v "__module_.*$(MODULE_NAME)" | $(AWK) "{print \$$8;}" | sort \
| grep -v edmac_format_size > localsyms)
$(call build,STRIP,$(OBJCOPY) edmac.mo edmac.mo --localize-symbols localsyms)
$(call rm_files, localsyms)
$(call build,EXPORTS,$(READELF) -sW $< | grep GLOBAL | grep -v UND | grep -v COM | grep -v "__module_.*$(MODULE_NAME)" | $(AWK) "{print \$$2 \" \" \$$8;}" | sort > $@ && cat $@)
EDmac tools
===========
EDMAC reverse engineering and diagnostic tools.
:Authors: a1ex, g3gg0
:License: GPL
:Summary: EDMAC reverse engineering and diagnostic tools.
#include <module.h>
#include <dryos.h>
#include <property.h>
#include <bmp.h>
#include <menu.h>
#include <console.h>
#include <shoot.h>
#include <beep.h>
#include <edmac.h>
#include <timer.h>
#include <asm.h>
extern WEAK_FUNC(ret_0) char * asm_guess_func_name_from_string(uint32_t func_addr);
static int edmac_selection;
static void edmac_display_page(int i0, int x0, int y0)
{
bmp_printf(
FONT_MONO_20,
x0, y0,
"EDM# Address Size\n"
);
y0 += fontspec_font(FONT_MONO_20)->height * 2;
for (int i = 0; i < 16; i++)
{
char msg[100];
int ch = i0 + i;
uint32_t addr = edmac_get_address(ch);
int state = edmac_get_state(ch);
struct edmac_info info = edmac_get_info(ch);
char * sz = edmac_format_size(&info);
if (strlen(sz) <= 10)
{
snprintf(msg, sizeof(msg), "[%2d] %8x: %s", ch, addr, sz);
}
else
{
snprintf(msg, sizeof(msg), "[%2d] %8x: %d", ch, addr, edmac_get_total_size(&info, 0));
}
if (state != 0 && state != 1)
{
STR_APPEND(msg, " (%x)", state);
}
uint32_t dir = edmac_get_dir(ch);
uint32_t conn_w = edmac_get_connection(ch, EDMAC_DIR_WRITE);
uint32_t conn_r = edmac_get_connection(ch, EDMAC_DIR_READ);
int color =
dir == EDMAC_DIR_UNUSED ? COLOR_GRAY(20) : /* unused? */
state == 0 ? COLOR_GRAY(50) : /* inactive? */
state == 1 ? COLOR_GREEN1 : /* active? */
COLOR_RED ; /* no idea */
if (dir == EDMAC_DIR_WRITE)
{
if (conn_w == 0)
{
/* Write EDMAC, but could not figure out where it's connected */
/* May be either unused, or connected to 0 (RAW data) */
STR_APPEND(msg, " <w!>");
}
else
{
STR_APPEND(msg, " <w%x>", conn_w);
}
}
else if (dir == EDMAC_DIR_READ)
{
if (conn_r == 0xFF)
{
/* Read EDMAC, but could not figure out where it's connected */
STR_APPEND(msg, " <r!>");
}
else
{
STR_APPEND(msg, " <r%x>", conn_r);
}
}
if (dir != EDMAC_DIR_UNUSED && strchr(msg, '!'))
{
color = COLOR_YELLOW;
}
bmp_printf(
FONT(FONT_MONO_20, color, COLOR_BLACK),
x0, y0 + i * fontspec_font(FONT_MONO_20)->height,
msg
);
}
}
static void edmac_display_detailed(int channel)
{
uint32_t base = edmac_get_base(channel);
int x = 50;
int y = 50;
bmp_printf(
FONT_LARGE,
x, y,
"EDMAC #%d - %x\n",
channel,
base
);
y += font_large.height;
/* http://magiclantern.wikia.com/wiki/Register_Map#EDMAC */
uint32_t dir = edmac_get_dir(channel);
char* dir_s =
dir == EDMAC_DIR_READ ? "read" :
dir == EDMAC_DIR_WRITE ? "write" :
"unused";
if (dir == EDMAC_DIR_UNUSED)
{
/* attempting to get info from unused channels may crash on old models */
/* if it doesn't crash, the additional info doesn't make any sense */
bmp_printf(FONT_MONO_20, 50, y + font_large.height, "Unused");
return;
}
uint32_t state = edmac_get_state(channel);
uint32_t flags = edmac_get_flags(channel);
uint32_t addr = edmac_get_address(channel);
char flags_desc[32] = "";
if (flags)
{
snprintf(flags_desc, sizeof(flags_desc),
"(%d bytes per transfer)",
edmac_bytes_per_transfer(flags)
);
}
union edmac_size_t
{
struct { short x, y; } size;
uint32_t raw;
};
union edmac_size_t size_n = (union edmac_size_t) shamem_read(base + 0x0C);
union edmac_size_t size_b = (union edmac_size_t) shamem_read(base + 0x10);
union edmac_size_t size_a = (union edmac_size_t) shamem_read(base + 0x14);
uint32_t off1b = shamem_read(base + 0x18);
uint32_t off2b = shamem_read(base + 0x1C);
uint32_t off1a = shamem_read(base + 0x20);
uint32_t off2a = shamem_read(base + 0x24);
uint32_t off3 = shamem_read(base + 0x28);
uint32_t off40 = shamem_read(base + 0x40);
uint32_t conn_w = edmac_get_connection(channel, EDMAC_DIR_WRITE);
uint32_t conn_r = edmac_get_connection(channel, EDMAC_DIR_READ);
struct edmac_info info = edmac_get_info(channel);
int fh = fontspec_font(FONT_MONO_20)->height;
bmp_printf(FONT_MONO_20, 50, y += fh, "Address : %8x ", addr);
bmp_printf(FONT_MONO_20, 50, y += fh, "State : %8x ", state);
bmp_printf(FONT_MONO_20, 50, y += fh, "Flags : %8x %s", flags, flags_desc);
bmp_printf(FONT_MONO_20, 50, y += fh, "Size : %s ", edmac_format_size(&info));
y += fh;
bmp_printf(FONT_MONO_20, 50, y += fh, "Size A : %8x (%d x %d) ", size_a.raw, size_a.size.x, size_a.size.y);
bmp_printf(FONT_MONO_20, 50, y += fh, "Size B : %8x (%d x %d) ", size_b.raw, size_b.size.x, size_b.size.y);
bmp_printf(FONT_MONO_20, 50, y += fh, "Size N : %8x (%d x %d) ", size_n.raw, size_n.size.x, size_n.size.y);
bmp_printf(FONT_MONO_20, 50, y += fh, "off1a : %8x ", off1a);
bmp_printf(FONT_MONO_20, 50, y += fh, "off1b : %8x ", off1b);
bmp_printf(FONT_MONO_20, 50, y += fh, "off2a : %8x ", off2a);
bmp_printf(FONT_MONO_20, 50, y += fh, "off2b : %8x ", off2b);
bmp_printf(FONT_MONO_20, 50, y += fh, "off3 : %8x ", off3);
bmp_printf(FONT_MONO_20, 50, y += fh, "off40 : %8x ", off40);
y += fh;
bmp_printf(FONT_MONO_20, 50, y += fh, "Connection : write=0x%x read=0x%x dir=%s", conn_w, conn_r, dir_s);
if (is_camera("5D3", "*"))
{
/**
* ConnectReadEDmac(channel, conn)
* RAM:edmac_register_interrupt(channel, cbr_handler, ...)
* => *(8 + 32*arg0 + *0x12400) = arg1
* and also: *(12 + 32*arg0 + *0x12400) = arg1
*/
uint32_t cbr1 = MEM(8 + 32*(channel) + MEM(0x12400));
uint32_t cbr2 = MEM(12 + 32*(channel) + MEM(0x12400));
bmp_printf(FONT_MONO_20, 50, y += fh, "CBR handler: %8x %s", cbr1, asm_guess_func_name_from_string(cbr1));
bmp_printf(FONT_MONO_20, 50, y += fh, "CBR abort : %8x %s", cbr2, asm_guess_func_name_from_string(cbr2));
}
}
static MENU_UPDATE_FUNC(edmac_display)
{
if (!info->can_custom_draw) return;
info->custom_drawing = CUSTOM_DRAW_THIS_MENU;
bmp_fill(COLOR_BLACK, 0, 0, 720, 480);
if (edmac_selection == 0 || edmac_selection == 1) // overview
{
if (edmac_selection == 0)
{
edmac_display_page(0, 0, 30);
edmac_display_page(16, 360, 30);
}
else
{
edmac_display_page(16, 0, 30);
if (edmac_get_dir(32) != EDMAC_DIR_UNUSED)
{
edmac_display_page(32, 360, 30);
}
}
bmp_printf(
FONT_MONO_20,
20, 450, "EDMAC state: "
);
bmp_printf(
FONT(FONT_MONO_20, COLOR_GRAY(50), COLOR_BLACK),
20+200, 450, "inactive"
);
bmp_printf(
FONT(FONT_MONO_20, COLOR_GREEN1, COLOR_BLACK),
20+350, 450, "running"
);
bmp_printf(
FONT_MONO_20,
720 - fontspec_font(FONT_MONO_20)->width * 13, 450, "[Scrollwheel]"
);
}
else // detailed view
{
edmac_display_detailed(edmac_selection - 2);
}
}
/* attempt to detect available edmac channels */
static volatile int trying_to_lock = 0;
static volatile int timed_out = 0;
static void check_timeout()
{
timed_out = 1;
if (lv && trying_to_lock)
{
int key_play = module_translate_key(MODULE_KEY_PLAY, MODULE_KEY_CANON);
fake_simple_button(key_play);
}
}
static int try_lock_edmac_channel(uint32_t resource)
{
uint32_t res[] = { resource };
struct LockEntry * resLock = CreateResLockEntry(res, 1);
/* the Lock call will block if the resource is used by someone else */
/* to get past it, try to enter PLAY mode after a timeout */
delayed_call(1000, check_timeout, 0);
timed_out = 0;
trying_to_lock = 1;
LockEngineResources(resLock);
trying_to_lock = 0;
UnLockEngineResources(resLock);
int success = !timed_out;
while (!timed_out)
msleep(10);
return success;
}
static void find_free_edmac_channels()
{
console_show();
msleep(2000);
for (int ch = 0; ch < 32; ch++)
{
force_liveview();
wait_lv_frames(5);
int dir = edmac_get_dir(ch);
int i = edmac_channel_to_index(ch);
uint32_t resource = 0;
switch (dir)
{
case EDMAC_DIR_WRITE:
{
printf("Trying write channel #%d... ", ch);
resource = 0x00000000 + i; /* write edmac channel */
break;
}
case EDMAC_DIR_READ:
{
printf("Trying read channel #%d... ", ch);
resource = 0x00010000 + i; /* read edmac channel */
break;
}
default:
{
printf("Skipping unused channel #%d...\n", ch);
continue;
}
}
if (try_lock_edmac_channel(resource))
{
printf("seems to work!\n");
}
else
{
printf("\n");
}
}
}
/* log EDMAC state every X microseconds */
static const int LOG_INTERVAL = 100;
/* a little faster when hardcoded */
/* should match edmac_chanlist from src/edmac.c */
static const int edmac_regs[] = {
0xC0F04000, 0xC0F04100, 0xC0F04200, 0xC0F04300, 0xC0F04400, 0xC0F04500, 0xC0F04600,
0xC0F04800, 0xC0F04900, 0xC0F04A00, 0xC0F04B00, 0xC0F04C00, 0xC0F04D00,
0xC0F26000, 0xC0F26100, 0xC0F26200, 0xC0F26300, 0xC0F26400, 0xC0F26500, 0xC0F26600,
0xC0F26800, 0xC0F26900, 0xC0F26A00, 0xC0F26B00, 0xC0F26C00, 0xC0F26D00,