--- include/script.h (revision 811) +++ include/script.h (working copy) @@ -24,4 +24,6 @@ extern int load_params_values(const char *fn, int update_vars, int read_param_set); extern void save_params_values(int unconditional); //------------------------------------------------------------------- + +extern void lua_script_exec(char *script); #endif --- include/platform.h (revision 811) +++ include/platform.h (working copy) @@ -498,4 +498,41 @@ #define started() debug_led(1) #define finished() debug_led(0) + + +typedef struct { + int code; + int sess_id; + int trans_id; + int num_param; + int param1; + int param2; + int param3; + int param4; + int param5; +} PTPContainer; + +typedef struct { + int handle; + int (*send_data)(int handle, char *buf, int size, int size_again, int, int, int); // (0xFF9F525C) + int (*recv_data)(int handle, char *buf, int size, int, int); // (0xFF9F5500) + int (*send_resp)(int handle, PTPContainer *resp); // (0xFF9F5688) + int (*get_data_size)(int handle); // (0xFF9F5830) + int (*send_err_resp)(int handle, PTPContainer *resp); // (0xFF9F5784) + int unknown1; // ??? + int (*f2)(); // ??? (0xFF8D5B24) + int (*f3)(); // ??? (0xFF8D5B5C) + // more?? +} ptp_data; + +typedef int (*ptp_handler)(int, ptp_data*, int, int, int, int, int, int, int, int); + +int add_ptp_handler(int opcode, ptp_handler handler, int unknown); + +void shutdown_soft(); +void reboot(char *fw_update); // fw_update == NULL implies normal reboot +void switch_mode(int mode); // 0 = playback, 1 = record; only call while USB connected + +void ExitTask(); + #endif --- include/core.h (revision 811) +++ include/core.h (working copy) @@ -19,5 +19,7 @@ long core_get_noise_reduction_value(); +void init_chdk_ptp(); + #endif --- include/lolevel.h (revision 811) +++ include/lolevel.h (working copy) @@ -232,4 +232,11 @@ extern void _ScreenLock(); // known in CHDK as _RefreshPhysicalScreen //extern void _ScreenUnLock(); + +extern int _add_ptp_handler(int, void*, int); +extern void _reboot_fw_update(char *); +extern void _set_control_event(int); +extern void _PB2Rec(); +extern void _Rec2PB(); + #endif --- platform/ixus870_sd880/lib.c (revision 811) +++ platform/ixus870_sd880/lib.c (working copy) @@ -94,3 +94,36 @@ { _RefreshPhysicalScreen(1); } + +void shutdown_soft() +{ + _PostLogicalEventForNotPowerType(0x1005,0); +} + +void reboot(char *fw_update) +{ + if ( fw_update == 0 ) + { + // sequence taken from reboot_fw_update + ((void (*)()) 0xFF94F7B8)(); + ((void (*)()) 0xFF842480)(); + ((void (*)()) 0xFF841594)(); + ((void (*)()) 0xFF8704F4)(); + ((void (*)(int)) 0xFF8293DC)(0); + } else { + _reboot_fw_update(fw_update); + } +} + +void switch_mode(int mode) +{ + if ( mode == 0 ) + { + _Rec2PB(); + _set_control_event(0x80000902); // 0x10A5 ConnectUSBCable + } else if ( mode == 1 ) + { + _set_control_event(0x902); // 0x10A6 DisconnectUSBCable + _PB2Rec(); + } +} --- platform/ixus870_sd880/sub/101a/stubs_entry_2.S (revision 811) +++ platform/ixus870_sd880/sub/101a/stubs_entry_2.S (working copy) @@ -36,6 +36,11 @@ NHSTUB(ScreenLock, 0xFF9B83D0) // via aScreenlock NHSTUB(MakeAFScan, 0xFF933E54) // via aSsprepareseqba (function with most uses) NHSTUB(ExpCtrlTool_StartContiAE, 0xFF830D00) // via aStartcontiae +NHSTUB(add_ptp_handler, 0xFF9EF744) // via ptp handler table +NHSTUB(set_control_event, 0xFF878894) // via eventproc_export_IsControlEventActive (last call) +NHSTUB(PB2Rec, 0xFF87BF0C) // via aAcPb2rec +NHSTUB(Rec2PB, 0xFF87A8A4) // via aAcRec2pb +NHSTUB(reboot_fw_update, 0xFFA296A0) // via aFirmupgrade_c // Corrections for uncertain entries in stubs_entry.S --- platform/ixus870_sd880/sub/101a/boot.c (revision 811) +++ platform/ixus870_sd880/sub/101a/boot.c (working copy) @@ -34,6 +34,9 @@ _CreateTask("SpyTask", 0x19, 0x2000, core_spytask, 0); }; +void CreateTask_init_chdk_ptp() { + _CreateTask("InitCHDKPTP", 0x19, 0x2000, init_chdk_ptp, 0); +}; void __attribute__((naked,noinline)) boot() { @@ -294,6 +297,7 @@ "BL sub_FF826C64\n" "BL sub_FF829898\n" "BL CreateTask_spytask\n" // + + "BL CreateTask_init_chdk_ptp\n" // + "BL sub_FF821848\n" // calls mykbd_task and JogDial_task // - SleepTask // - JogDialTask --- platform/generic/wrappers.c (revision 811) +++ platform/generic/wrappers.c (working copy) @@ -947,3 +947,13 @@ void __attribute__((weak)) vid_turn_on_updates() { } + +int add_ptp_handler(int opcode, ptp_handler handler, int unknown) +{ + return _add_ptp_handler(opcode,handler,unknown); +} + +void ExitTask() +{ + _ExitTask(); +} --- core/Makefile (revision 811) +++ core/Makefile (working copy) @@ -56,7 +56,7 @@ gui_fselect.o gui.o kbd.o conf.o \ histogram.o gui_batt.o gui_space.o gui_osd.o script.o raw.o \ gui_lang.o gui_mpopup.o gui_grid.o motion_detector.o raw_merge.o \ - luascript.o shot_histogram.o dng.o $(OPT_OBJS) + luascript.o shot_histogram.o dng.o ptp.o $(OPT_OBJS) gui.o: FORCE --- core/ptp.c (revision 0) +++ core/ptp.c (revision 0) @@ -0,0 +1,395 @@ +#include "platform.h" +#include "stdlib.h" +#include "ptp.h" +#include "script.h" + +int handle_ptp(int h, ptp_data *data, int opcode, int sess_id, int trans_id, + int param1, int param2, int param3, int param4, int param5); + +void init_chdk_ptp() +{ + int r; + + // wait until ptp_handlers_info is initialised and add CHDK PTP interface + r = 0x17; + while ( r==0x17 ) + { + r = add_ptp_handler(PTP_OC_CHDK,handle_ptp,0); + msleep(250); + } + + ExitTask(); +} + +int handle_ptp(int h, ptp_data *data, int opcode, int sess_id, int trans_id, + int param1, int param2, int param3, int param4, int param5) +{ + static char *temp_data = NULL; + static int temp_data_size = 0; + PTPContainer ptp; + + // initialise default response + memset(&ptp,0,sizeof(PTPContainer)); + ptp.code = PTP_RC_OK; + ptp.sess_id = sess_id; + ptp.trans_id = trans_id; + ptp.num_param = 0; + + // handle command + switch ( param1 ) + { + + case PTP_CHDK_Shutdown: + ptp.code = PTP_RC_GeneralError; // default in case shutdown/reboot fails + switch ( param2 ) + { + case 0: // hard shutdown + shutdown(); + break; + case 1: // soft shutdown + shutdown_soft(); + ptp.code = PTP_RC_OK; // shutdown is not immediate + break; + case 2: // reboot + reboot(NULL); + break; + case 3: // reboot using firmware update + { + FILE *f; + int s = data->get_data_size(data->handle); + char *fn = (char *) malloc(s+1); + + sprintf(fn,"%i",s); + script_console_add_line(fn); + if ( fn == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + fn[s] = '\0'; + + data->recv_data(data->handle,fn,s,0,0); + + if ( s == 0 ) + { + free(fn); + fn = "A/PS.FI2"; + } + + if ( (f = fopen(fn,"rb")) == NULL ) + { + ptp.code = PTP_RC_GeneralError; + } else { + fclose(f); + reboot(fn); + } + + if ( s != 0 ) + { + free(fn); + } + break; + } + default: + ptp.code = PTP_RC_ParameterNotSupported; + break; + } + break; + + case PTP_CHDK_GetMemory: + { + if ( param2 == 0 || param3 < 1 ) // null pointer or invalid size? + { + ptp.code = PTP_RC_GeneralError; + break; + } + + if ( data->send_data(data->handle,(char *) param2,param3,param3,0,0,0) ) + { + ptp.code = PTP_RC_GeneralError; + } + break; + } + + case PTP_CHDK_SetMemoryLong: + *((volatile long *) param2) = param3; + break; + + case PTP_CHDK_CallFunction: + { + int s; + int *buf = (int *) malloc((10+1)*sizeof(int)); + + if ( buf == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + + s = data->get_data_size(data->handle); + data->recv_data(data->handle,(char *) buf,s,0,0); + + ptp.num_param = 1; + ptp.param1 = ((int (*)(int,int,int,int,int,int,int,int,int,int)) buf[0])(buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10]); + + free(buf); + break; + } + + case PTP_CHDK_GetPropCase: + { + int *buf, i; + + if ( param3 < 1 ) // invalid number of properties + { + ptp.code = PTP_RC_GeneralError; + break; + } + + buf = (int *) malloc(param3*sizeof(int)); + if ( buf == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + + for (i=0; isend_data(data->handle,(char *) buf,param3*sizeof(int),param3*sizeof(int),0,0,0) ) + { + ptp.code = PTP_RC_GeneralError; + } + free(buf); + break; + } + + case PTP_CHDK_GetParamData: + { + extern long* FlashParamsTable[]; + char *buf, *p; + int i, s; + + if ( param3 < 1 ) // invalid number of parameters + { + ptp.code = PTP_RC_GeneralError; + break; + } + + // calculate required size for all properties (and lengths) + s = 0; + for (i=0; i>16); // room for size and actual data + } + + buf = (char *) malloc(s); + if ( buf == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + + // construct result + p = buf; + for (i=0; i>16; + // write size + memcpy(p,&t,4); + p += 4; + // write value + get_parameter_data(param2+i,p,t); + p += t; + } + + if ( data->send_data(data->handle,buf,s,s,0,0,0) ) + { + ptp.code = PTP_RC_GeneralError; + } + free(buf); + break; + } + + case PTP_CHDK_TempData: + if ( temp_data != NULL ) + { + free(temp_data); + temp_data = NULL; + } + + temp_data_size = data->get_data_size(data->handle); + + temp_data = (char *) malloc(temp_data_size); + if ( temp_data == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + + data->recv_data(data->handle,temp_data,temp_data_size,0,0); + + break; + + case PTP_CHDK_UploadFile: + { + FILE *f; + int s,r,fn_len; + char *buf, *fn; + + s = data->get_data_size(data->handle); + + data->recv_data(data->handle,(char *) &fn_len,4,0,0); + s -= 4; + + fn = (char *) malloc(fn_len+1); + if ( fn == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + fn[fn_len] = '\0'; + + data->recv_data(data->handle,fn,fn_len,0,0); + s -= fn_len; + + f = fopen(fn,"wb"); + if ( f == NULL ) + { + ptp.code = PTP_RC_GeneralError; + free(fn); + break; + } + free(fn); + +#define BUF_SIZE 4096 + buf = (char *) malloc(BUF_SIZE); + if ( buf == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + while ( s > 0 ) + { + if ( s >= BUF_SIZE ) + { + r = data->recv_data(data->handle,buf,BUF_SIZE,0,0); + fwrite(buf,1,BUF_SIZE,f); + s -= BUF_SIZE; + } else { + data->recv_data(data->handle,buf,s,0,0); + fwrite(buf,1,s,f); + s = 0; + } + } + + fclose(f); + + free(buf); + break; + } + + case PTP_CHDK_DownloadFile: + { + FILE *f; + int s,r,fn_len; + char *buf, *fn; + + if ( temp_data == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + + fn = (char *) malloc(temp_data_size+1); + if ( fn == NULL ) + { + free(temp_data); + temp_data = NULL; + ptp.code = PTP_RC_GeneralError; + break; + } + memcpy(fn,temp_data,temp_data_size); + fn[temp_data_size] = '\0'; + + free(temp_data); + temp_data = NULL; + + f = fopen(fn,"rb"); + if ( f == NULL ) + { + ptp.code = PTP_RC_GeneralError; + free(fn); + break; + } + free(fn); + + fseek(f,0,SEEK_END); + s = ftell(f); + fseek(f,0,SEEK_SET); + + buf = (char *) malloc(s); + if ( buf == NULL ) + { + ptp.code = PTP_RC_GeneralError; + fclose(f); + break; + } + + fread(buf,1,s,f); + fclose(f); + + data->send_data(data->handle,buf,s,s,0,0,0); + ptp.num_param = 1; + ptp.param1 = s; + + free(buf); + + break; + } + break; + + case PTP_CHDK_SwitchMode: + if ( param2 != 0 && param2 != 1 ) + { + ptp.code = PTP_RC_ParameterNotSupported; + } else { + switch_mode(param2); + } + break; + + case PTP_CHDK_ExecuteLUA: + { + int s; + char *buf; + + s = data->get_data_size(data->handle); + + buf = (char *) malloc(s); + if ( buf == NULL ) + { + ptp.code = PTP_RC_GeneralError; + break; + } + + data->recv_data(data->handle,buf,s,0,0); + + lua_script_exec(buf); + + free(buf); + + break; + } + + default: + ptp.code = PTP_RC_ParameterNotSupported; + break; + } + + // send response + data->send_resp( data->handle, &ptp ); + + return 1; +} --- core/ptp.h (revision 0) +++ core/ptp.h (revision 0) @@ -0,0 +1,34 @@ +#ifndef __PTP_H +#define __PTP_H + +#define PTP_OC_CHDK 0x9999 + +#define PTP_RC_OK 0x2001 +#define PTP_RC_GeneralError 0x2002 +#define PTP_RC_ParameterNotSupported 0x2006 + +enum { + PTP_CHDK_Shutdown = 0, // param2 is 0 (hard), 1 (soft), 2 (reboot) or 3 (reboot fw update) + // if param2 == 3, then filename of fw update is send as data (empty for default) + PTP_CHDK_GetMemory, // param2 is base address (not NULL; circumvent by taking 0xFFFFFFFF and size+1) + // param3 is size (in bytes) + // return data is memory block + PTP_CHDK_SetMemoryLong, // param2 is address + // param3 is value + PTP_CHDK_CallFunction, // data is array of function pointer and (long) arguments (max: 10 args) + // return param1 is return value + PTP_CHDK_GetPropCase, // param2 is base id + // param3 is number of properties + // return data is array of longs + PTP_CHDK_GetParamData, // param2 is base id + // param3 is number of parameters + // return data is sequence of strings prefixed by their length (as long) + PTP_CHDK_TempData, // data is data to be stored for later + PTP_CHDK_UploadFile, // data is 4-byte length of filename, followed by filename and contents + PTP_CHDK_DownloadFile, // preceded by PTP_CHDK_TempData with filename + // return data are file contents + PTP_CHDK_SwitchMode, // param2 is 0 (playback) or 1 (record) + PTP_CHDK_ExecuteLUA, // data is script to be executed +} ptp_chdk_command; + +#endif // __PTP_H --- core/kbd.c (revision 811) +++ core/kbd.c (working copy) @@ -246,6 +246,15 @@ return 1; } +void lua_script_exec( char *script ) +{ + lua_script_start(script); + state_lua_kbd_first_call_to_resume = 1; + state_kbd_script_run = 1; + kbd_blocked = 1; +} + + static void wait_and_end(void) { script_console_add_line("PRESS SHUTTER TO CLOSE");