My older attempt at 700D in QEMU (I've used it to understand how 5D3 TTJ works):
if (is_camera("700D", "1.1.4"))
{
/* uses TwoInTwoOutJpegPath, but functions are mostly compatible */
TTL_SetArgs = (void *) 0xFF35F510; /* fills TTJ_Args struct; PictureSize(Mem1ToRaw) */
TTL_Prepare = (void *) 0xFF424BA4; /* called right after StartTwoInTwoOutJpegPath Raw(R) Start(%d) */
/* calls [TTJ] GetPathResources and sets up the encoder for RAW */
TTL_RegisterCBR = (void *) 0xFF423B88; /* RegisterTwoInTwoOutJpegPathCompleteCBR */
TTL_SetFlags = (void *) set_flags_700D; /* this function is inline on 700D */
TTL_Start = (void *) 0xFF424C4C; /* called next; starts the EDmac transfers */
TTL_Stop = (void *) 0xFF423DD4; /* called after sdfStopYuvToJpegPath(%d); unsure, need a dm-spy log */
TTL_Finish = (void *) 0xFF424CBC; /* called next; calls UnlockEngineResources and returns output size from JpCoreCompleteCBR */
TTL_ResLock = (void *) MEM(0x25A60); /* this should work outside LiveView (e.g. full-res silent pics) */
}
static void set_flags_700D()
{
EngDrvOut(0xC0F37010, (shamem_read(0xC0F37010) & 0xFFE3FFFF) | 0xC0000);
EngDrvOut(0xC0F3704C, (shamem_read(0xC0F3704C) & 0xFFFFFFC0) | 0x20);
EngDrvOut(0xC0F37074, (shamem_read(0xC0F37074) & 0xFFC0FFFF) | 0x180000);
EngDrvOut(0xC0F37078, (shamem_read(0xC0F37078) & 0xFFC0FFFF) | 0x180000);
}
As dfort guessed, all of this is found by following Canon's CR2 compression routines (codenamed Mem1ToRaw). Unfortunately, there are differences between models, so it's not always just a pattern matching.
You've noticed ResLock requires some tweaking. What's up with it?ResLock is a way to lock certain image processing modules (or "resources") that we are going to use (in order to prevent two tasks from using that image processing module at the same time). Each image processing "resource" is identified by a 32-bit resource ID (aka resID). From those, the most significant 16 bits are the class ID (category of resource), and the least significant bits are the resource ID within that class. Here you can find
the known resource identifiers.
Each ResLock ID has an (internal) semaphore associated. Some resources (such as EDMAC channels / connections) may work without locking, as long as only one task uses them (otherwise you get corrupted data), but the compression ones refuse to work that way. Apparently, LockEngineResources also enables the clocks required by certain resources (it probably powers up the hardware required by those operations).
The first step is to try Canon's ResLock configuration outside LiveView (where all image processing resources are free, so their default reslock setup is likely to work).
What about LiveView?In LiveView, many EDMAC channels are already assigned and locked (by Canon code); they will probably conflict with the choice used for CR2 compression (which is done outside LiveView). That means, we'll have to re-assign the EDMAC channels (and a good choice is to reuse the channels from edmac-memcpy.c, since they won't be used at the same time anyway).
On 5D3, I only had to redirect the write channel, but for a portable solution, the read channel might have to be redirected as well.
On this camera, the list of resources is found in TTL_SetArgs, for PictureSize == 0:
0x10000, // RD1: first read channel (EDMAC channel 8) - didn't have to change it
0xD, // WR1: write channel #13 (look it up in edmac_chanlist - it's channel 22; changed to channel 17 for LiveView)
2, // WR2: write channel #2 (unused, deleted; didn't check what data it outputs)
0x30001, // connection 1; don't remember why I've deleted it (possibly by mistake)
0x2002d ... 0x260003 // unknown, copied verbatim
On 700D, the list is at 0x334E4 (e.g. in a RAM dump).
For reference, here's the
TTJ version for 5D3 1.2.3 (works only outside LiveView; code based on 700D):
if (is_camera("5D3", "1.2.3"))
{
/* ProcessTwoInTwoOutJpegPath, 5D3 1.2.3 */
TTL_SetArgs = (void *) 0xFF327DE8; /* using TTL version */
TTL_Prepare = (void *) 0xFF3D00A0; /* called between sdfExecuteYuvToJpegPath and StartYuvToJpegPath */
TTL_RegisterCBR = (void *) 0xFF3CF084; /* RegisterTwoInTwoOutJpegPathCompleteCBR */
TTL_SetFlags = (void *) set_flags_700D; /* using 700D version */
TTL_Start = (void *) 0xFF3D0148; /* called after StartYuvToJpegPath; starts the EDmac transfers */
TTL_Stop = (void *) 0xFF3D0180; /* called right after sssStopMem1ToJpegPath */
TTL_Finish = (void *) 0xFF3D01B8; /* called next; calls UnlockEngineResources and returns output size from JpCoreCompleteCBR */
}
uint32_t resources[] = {
0x10000, /* read channel 0x8 */
edmac_channel_to_index(0x11), /* write channel 0x11 */
0x30002, /* read conn 2 */
0x20005, /* write conn 5 */
0x50034,
0x5002D,
0x50010,
0x90001,
0x90000,
0xA0000,
0x160000,
0x260000,
0x260001,
0x260002,
0x260003,
};
/* copy this one from 0x33528 until 0x33918 (700D 1.1.4) */
TTL_Args.engio_cmd_1_prepare = prepare_700D;
Overriding resolution is a different story; let's first get it working in full-res mode (Canon hard-codes resolution parameters for a full-res raw buffer). You may have to comment out the EngDrvOut calls for overriding the resolution, and maybe also the EDMAC setup for RD1.
OK, what's up with those funny names like RD1, WR1 etc?From the name: TwoInTwoOut means this routine accepts two inputs (RD1, RD2) and two outputs (WR1, WR2). All of them are optional (see TTL_Start and TTL_Stop - these channels are only configured if the corresponding address or memsuite from TTL_Args is nonzero).
For lossless compression, we are interested in RD1 and WR1. What the others do, I don't know.
The default configuration (CR2 with quality set to RAW) uses RD1, WR1 and WR2. On 5D3, they use EDMAC channels 8, 22 and 2 (look at
this picture).
RD1 reads from a contiguous buffer (that's the 14-bit raw buffer in the default configuration). In the picture, you can see it appears to scan the image twice, and its size looks a bit unusual.
Here's how to decipher it and why we are overriding it.
WR1 uses a memSuite (unlike the other channels) - this is a data structure in Canon firmware that can contain one or more contiguous memChunk's (in other words, the WR1 channel can write to fragmented memory, possibly allocated with *_malloc_suite routines from exmem.c). The output size is not known in advance - it is set by TTL_Finish (actually JpCoreCompleteCBR). If the size is larger, it will not overflow the memSuite, but apparently
there are weird alignment constraints on its size.
WR2 outputs something of size 1776*2 x 394 bytes, but didn't try to decode it (probably some sort of preview). Unused in our routine.
Here's a debug log from 5D3, showing the CR2 compression (among many others). Some relevant lines:
ShootSsDev:ff162e10:a7:03: sssExecuteMem1ToRawPath(79319)
ShootSsDev:ff163230:a7:03: ProcessTwoInTwoOutLosslessPath(R) Start(79319)
ShootSsDev:ff3d3f34:16:03: [TTL][167,79319,0] RAW(5920,3950,0,14)
ShootSsDev:000afe98:00:00: *** StartEDmac(0x16, 0x0), from ff576498
ShootSsDev:000afe98:00:00: *** StartEDmac(0x2, 0x0), from ff3d3af0
ShootSsDev:000afe98:00:00: *** StartEDmac(0x8, 0x2), from ff3d3b50
**INT-A3h*:ff3d3d14:16:03: [TTL][167,79319,0] JpCoreCompleteCBR( 0x146a56b )
To be continued.