From c51245629490ce6af79521763eb35dd738f31838 Mon Sep 17 00:00:00 2001 From: "mr_wicked@hotmail.com" Date: Tue, 3 Jan 2012 11:14:07 +0000 Subject: [PATCH] merged SACD Daemon into SACD Ripper --- Makefile | 2 +- libs/libcommon/sys/storage.h | 1 + libs/libsacd/ioctl.c | 17 ++ libs/libsacd/ioctl.h | 1 + libs/libsacd/sacd_input.c | 39 ++- src/main.c | 136 ++++++++- tools/Makefile | 2 +- tools/sacd_daemon/Makefile | 148 ---------- tools/sacd_daemon/bin/ICON0.PNG | Bin 31641 -> 0 bytes tools/sacd_daemon/bin/sfo.xml | 34 --- tools/sacd_daemon/src/exit_handler.c | 70 ----- tools/sacd_daemon/src/exit_handler.h | 28 -- tools/sacd_daemon/src/main.c | 408 -------------------------- tools/sacd_daemon/src/output_device.c | 97 ------ tools/sacd_daemon/src/output_device.h | 42 --- tools/sacd_daemon/src/rsxutil.c | 173 ----------- tools/sacd_daemon/src/rsxutil.h | 49 ---- tools/sacd_daemon/src/server.c | 278 ------------------ tools/sacd_daemon/src/server.h | 28 -- 19 files changed, 187 insertions(+), 1366 deletions(-) delete mode 100644 tools/sacd_daemon/Makefile delete mode 100644 tools/sacd_daemon/bin/ICON0.PNG delete mode 100644 tools/sacd_daemon/bin/sfo.xml delete mode 100644 tools/sacd_daemon/src/exit_handler.c delete mode 100644 tools/sacd_daemon/src/exit_handler.h delete mode 100644 tools/sacd_daemon/src/main.c delete mode 100644 tools/sacd_daemon/src/output_device.c delete mode 100644 tools/sacd_daemon/src/output_device.h delete mode 100644 tools/sacd_daemon/src/rsxutil.c delete mode 100644 tools/sacd_daemon/src/rsxutil.h delete mode 100644 tools/sacd_daemon/src/server.c delete mode 100644 tools/sacd_daemon/src/server.h diff --git a/Makefile b/Makefile index 0e0e9f05..597d0530 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -lrsx -lgcm_sys -lio -lsysmodule -lsysutil -lrt -llv2 -lm -lunself -lpatchutils -lsacd -lsysfs -lcommon -lid3 -lz -liconv -lnet +LIBS := -lrsx -lgcm_sys -lio -lsysmodule -lsysutil -lrt -llv2 -lm -lunself -lpatchutils -lsacd -lsysfs -lcommon -lid3 -lz -liconv -lnet -lnetctl #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing diff --git a/libs/libcommon/sys/storage.h b/libs/libcommon/sys/storage.h index 9090debb..249292d7 100644 --- a/libs/libcommon/sys/storage.h +++ b/libs/libcommon/sys/storage.h @@ -50,6 +50,7 @@ extern "C" { #define GPCMD_READ_TOC_PMA_ATIP 0x43 #define GPCMD_REPORT_KEY 0xa4 #define GPCMD_SEND_KEY 0xa3 +#define GPCMD_START_STOP_UNIT 0x1b #define LV2_STORAGE_SEND_ATAPI_COMMAND (1) diff --git a/libs/libsacd/ioctl.c b/libs/libsacd/ioctl.c index 1f194bf4..98a6ca58 100644 --- a/libs/libsacd/ioctl.c +++ b/libs/libsacd/ioctl.c @@ -24,6 +24,23 @@ #include #include "ioctl.h" +int ioctl_eject(int fd) +{ + int res; + struct lv2_atapi_cmnd_block atapi_cmnd; + static uint8_t buffer[256]; + memset(buffer, 0, sizeof(buffer)); + + sys_storage_init_atapi_cmnd(&atapi_cmnd, 0, ATAPI_PIO_DATA_OUT_PROTO, ATAPI_DIR_WRITE); + + atapi_cmnd.pkt[0] = GPCMD_START_STOP_UNIT; + atapi_cmnd.pkt[4] = 0x02; /* eject */ + + res = sys_storage_send_atapi_command(fd, &atapi_cmnd, buffer); + + return res; +} + int ioctl_get_configuration(int fd, uint8_t *buffer) { int res; diff --git a/libs/libsacd/ioctl.h b/libs/libsacd/ioctl.h index 7cf9b591..4663fe1c 100644 --- a/libs/libsacd/ioctl.h +++ b/libs/libsacd/ioctl.h @@ -31,6 +31,7 @@ extern "C" { #endif +extern int ioctl_eject(int fd); extern int ioctl_init(int fd, uint8_t *buffer); extern int ioctl_enable_encryption(int fd, uint8_t *buffer, uint32_t lba); extern int ioctl_get_configuration(int fd, uint8_t *buffer); diff --git a/libs/libsacd/sacd_input.c b/libs/libsacd/sacd_input.c index 04e8713e..923fc5d7 100644 --- a/libs/libsacd/sacd_input.c +++ b/libs/libsacd/sacd_input.c @@ -61,6 +61,7 @@ uint32_t (*sacd_input_total_sectors)(sacd_input_t); struct sacd_input_s { int fd; + uint8_t *input_buffer; #if defined(__lv2ppu__) device_info_t device_info; #endif @@ -339,6 +340,13 @@ static sacd_input_t sacd_net_input_open(const char *target) return NULL; } + dev->input_buffer = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); + if (dev->input_buffer == NULL) + { + fprintf(stderr, "libsacdread: Could not allocate memory.\n"); + goto error; + } + socket_open(); socket_create(&dev->fd, AF_INET, SOCK_STREAM, 0); @@ -380,6 +388,7 @@ static sacd_input_t sacd_net_input_open(const char *target) error: sacd_input_close(dev); + free(dev->input_buffer); free(dev); return 0; @@ -425,6 +434,10 @@ static int sacd_net_input_close(sacd_input_t dev) socket_destroy(&dev->fd); socket_close(); + if (dev->input_buffer) + { + free(dev->input_buffer); + } free(dev); return 0; @@ -505,12 +518,36 @@ static ssize_t sacd_net_input_read(sacd_input_t dev, int pos, int blocks, void * return 0; } +#if 0 + response.data.bytes = buffer; + { + size_t got; + uint8_t *buf_ptr = dev->input_buffer; + size_t buf_left = blocks * SACD_LSN_SIZE + 16; + + input = pb_istream_from_buffer(dev->input_buffer, MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); + + if (socket_recv(&dev->fd, (char *) buf_ptr, buf_left, &got, MSG_PARTIAL, 0) != IO_DONE) + return 0; + + while(got > 0 && !pb_decode(&input, ServerResponse_fields, &response)) + { + buf_ptr += got; + buf_left -= got; + + if (socket_recv(&dev->fd, (char *) buf_ptr, buf_left, &got, MSG_PARTIAL, 0) != IO_DONE) + return 0; + + input = pb_istream_from_buffer(dev->input_buffer, MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); + } + } +#else response.data.bytes = buffer; if (!pb_decode(&input, ServerResponse_fields, &response)) { return 0; } - +#endif if (response.type != ServerResponse_Type_DISC_READ) { return 0; diff --git a/src/main.c b/src/main.c index face2979..8856115f 100644 --- a/src/main.c +++ b/src/main.c @@ -38,6 +38,9 @@ #include #include +#include +#include + #include #include #include @@ -52,9 +55,11 @@ #include "exit_handler.h" #include "install.h" #include "output_device.h" +#include "server.h" #include "ripping.h" #include +#include #define MAX_PHYSICAL_SPU 6 #define MAX_RAW_SPU 1 @@ -278,6 +283,58 @@ static void bd_insert_disc_callback(uint32_t disc_type, char *title_id) } } +void server_loop(void) +{ + int client_connected; + msgType dialog_type; + char *message = (char *) malloc(512); + + // did the disc change? + if (bd_contains_sacd_disc && bd_disc_changed) + { + bd_contains_sacd_disc = 0; + } + + // by default we have no user controls + dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_DISABLE_CANCEL_ON); + + if (!bd_contains_sacd_disc) + { + union net_ctl_info info; + + if(netCtlGetInfo(NET_CTL_INFO_IP_ADDRESS, &info) == 0) + { + sprintf(message, " SACD Daemon %s\n\n" + "Status: Active\n" + "IP Address: %s (port 2002)\n" + "Client: %s\n" + "Disc: %s", + SACD_RIPPER_VERSION_STRING, info.ip_address, + (is_client_connected() ? "connected" : "none"), + (bd_disc_changed == -1 ? "empty" : "inserted")); + } + else + { + sprintf(message, "No active network connection was detected.\n\nPress OK to refresh."); + dialog_type |= MSG_DIALOG_BTN_TYPE_OK; + } + } + + msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL); + + dialog_action = 0; + bd_disc_changed = 0; + client_connected = is_client_connected(); + while (!dialog_action && !user_requested_exit() && bd_disc_changed == 0 && client_connected == is_client_connected()) + { + sysUtilCheckCallback(); + flip(); + } + msgDialogAbort(); + + free(message); +} + void main_loop(void) { msgType dialog_type; @@ -498,16 +555,37 @@ void show_version(void) msgDialogAbort(); } +int user_select_server_mode(void) +{ + msgType dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_YESNO | MSG_DIALOG_DISABLE_CANCEL_ON); + msgDialogOpen2(dialog_type, "Would you like to run in server mode?", dialog_handler, NULL, NULL); + msgDialogClose(5000.0f); + + dialog_action = 0; + while (!dialog_action && !user_requested_exit()) + { + sysUtilCheckCallback(); + flip(); + } + msgDialogAbort(); + + return dialog_action != 2; +} + int main(int argc, char *argv[]) { - int ret; + int ret, server_mode; void *host_addr = memalign(1024 * 1024, HOST_SIZE); msgType dialog_type; + sys_ppu_thread_t id; // start server thread load_modules(); init_logging(); + netInitialize(); + netCtlInit(); + // Initialize SPUs LOG(lm_main, LOG_DEBUG, ("Initializing SPUs\n")); ret = sysSpuInitialize(MAX_PHYSICAL_SPU, MAX_RAW_SPU); @@ -592,19 +670,60 @@ int main(int argc, char *argv[]) sys_storage_reset_bd(); sys_storage_authenticate_bd(); + // eject current disc + { + int fd; + ret = sys_storage_open(BD_DEVICE, &fd); + if (ret == 0) + { + ioctl_eject(fd); + sys_storage_close(fd); + } + } + ret = sysDiscRegisterDiscChangeCallback(&bd_eject_disc_callback, &bd_insert_disc_callback); // poll for an output_device poll_output_devices(); - while (1) - { - // main loop - main_loop(); + server_mode = user_select_server_mode(); - // break out of the loop when requested - if (user_requested_exit()) - break; + if (user_requested_exit()) + goto quit; + + if (server_mode) + { +#ifdef ENABLE_LOGGING + if (output_device) + { + char file_path[100]; + sprintf(file_path, "%s/daemon_log.txt", output_device); + set_log_file(file_path); + } +#endif + sysThreadCreate(&id, listener_thread, NULL, 1500, 0x400, 0, "listener"); + + while (1) + { + // server loop + server_loop(); + + // break out of the loop when requested + if (user_requested_exit()) + break; + } + } + else + { + while (1) + { + // main loop + main_loop(); + + // break out of the loop when requested + if (user_requested_exit()) + break; + } } ret = sysDiscUnregisterDiscChangeCallback(); @@ -614,6 +733,7 @@ int main(int argc, char *argv[]) unpatch_lv1_ss_services(); destroy_logging(); + netDeinitialize(); unload_modules(); free(host_addr); diff --git a/tools/Makefile b/tools/Makefile index 55aaeb92..0daa3794 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,4 +1,4 @@ -TARGETS := analysis_dump sacd_daemon +TARGETS := analysis_dump all: @for TARGET in $(TARGETS); do $(MAKE) --no-print-directory -C $$TARGET; done diff --git a/tools/sacd_daemon/Makefile b/tools/sacd_daemon/Makefile deleted file mode 100644 index 7f41a3dd..00000000 --- a/tools/sacd_daemon/Makefile +++ /dev/null @@ -1,148 +0,0 @@ -#--------------------------------------------------------------------------------- -# Clear the implicit built in rules -#--------------------------------------------------------------------------------- -.SUFFIXES: -#--------------------------------------------------------------------------------- -ifeq ($(strip $(PSL1GHT)),) -$(error "Please set PSL1GHT in your environment. export PSL1GHT=") -endif - -include $(PSL1GHT)/ppu_rules - -TITLE := SACD Daemon -APPID := SACDDAE01 -CONTENTID := UP0001-$(APPID)_00-0000000000000000 -SFOXML := ../bin/sfo.xml -ICON0 := ../bin/ICON0.PNG - -#--------------------------------------------------------------------------------- -# TARGET is the name of the output -# BUILD is the directory where object files & intermediate files will be placed -# SOURCES is a list of directories containing source code -# INCLUDES is a list of directories containing extra header files -#--------------------------------------------------------------------------------- -TARGET := $(notdir $(CURDIR)) -TARGETS := -BUILD := build -SOURCES := src -DATA := -INCLUDES := src ../../libs/libpatchutils ../../libs/libcommon ../../libs/libsacd - -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- - -CFLAGS = -O2 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) -DAPPID=$(APPID) -CXXFLAGS = $(CFLAGS) - -LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map - -#--------------------------------------------------------------------------------- -# any extra libraries we wish to link with the project -#--------------------------------------------------------------------------------- -LIBS := -lrsx -lgcm_sys -lio -lsysmodule -lsysutil -lrt -llv2 -lm -lpatchutils -lsysfs -lsacd -lcommon -lnet -lnetctl -liconv - -#--------------------------------------------------------------------------------- -# list of directories containing libraries, this must be the top level containing -# include and lib -#--------------------------------------------------------------------------------- -LIBDIRS := $(PORTLIBS) ../../../libs/libpatchutils ../../../libs/libcommon ../../../libs/libsacd - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- - -export OUTPUT := $(CURDIR)/$(TARGET) - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -export DEPSDIR := $(CURDIR)/$(BUILD) - -export BUILDDIR := $(CURDIR)/$(BUILD) - -#--------------------------------------------------------------------------------- -# automatically build a list of object files for our project -#--------------------------------------------------------------------------------- -CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) -CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) -sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) - -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) - export LD := $(CC) -else - export LD := $(CXX) -endif - -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ - $(sFILES:.s=.o) $(SFILES:.S=.o) - -#--------------------------------------------------------------------------------- -# build a list of include paths -#--------------------------------------------------------------------------------- -export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - $(LIBPSL1GHT_INC) \ - -I$(CURDIR)/$(BUILD) - -#--------------------------------------------------------------------------------- -# build a list of library paths -#--------------------------------------------------------------------------------- -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ - -L../../../libs/libiconv/lib/.libs/ \ - $(LIBPSL1GHT_LIB) - -export OUTPUT := $(CURDIR)/$(TARGET) -.PHONY: $(BUILD) clean - -#--------------------------------------------------------------------------------- -$(BUILD): - @for TARGET in $(TARGETS); do $(MAKE) --no-print-directory -C $$TARGET; done - @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @for TARGET in $(TARGETS); do $(MAKE) --no-print-directory -C $$TARGET clean; done - @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self - -#--------------------------------------------------------------------------------- -run: - ps3load $(OUTPUT).self - - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -$(OUTPUT).pkg: $(OUTPUT).self -$(OUTPUT).self: $(OUTPUT).elf -$(OUTPUT).elf: $(OFILES) - -#--------------------------------------------------------------------------------- -# This rule links in binary data with the .bin extension -#--------------------------------------------------------------------------------- -%.bin.o : %.bin -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - @$(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- diff --git a/tools/sacd_daemon/bin/ICON0.PNG b/tools/sacd_daemon/bin/ICON0.PNG deleted file mode 100644 index f01f4df0975f9d6f31ca08b931124892c2052ac5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31641 zcmZsCbyOV97v+5dLt zOw-eI4&7Dt>eapX-HKLKmc>9NK?Q+881iyb5D*AP3^=bvMg)!l?#)QR9~f7NtOTff zlI$Pw1<~}AtQ6?&zjtA0c?xg^#Ys-b6$C=V`|kq-%FZPQE+V5sPU|G{efRfXr+2%Tw=eS%%=kZQ@itLoVCB_PrPTIlbpA+K>)tl- zc<9YKed{-god30+ZDJL`WH+{5*RMG;mvG)-cjq?JwDzmCY5iAAlpsPfJm0aP>Sr-F zN9c#E_AA=OJ5W-R6e?93<#rv##@8EWqrFkrGvPaZD#MEyt&YD0HC}@(|KHOi`xeFx zgo`%VM6Lu+oeon_+@hX!G!muX^nsgz4|CdV?BF*C9Zd-Zods^Tsv{ryMfdn9Ivj#% zMikKaxYQptg?aK}wI+KkyH!JHvhww_JFU{xPR&YlPXTh4G=-b)>r#$okVZ%QHUXS* z2m8LWB$mj%akVz9CXW&+AG#T8j~#uQt|ReKoC9%6o5@ZTV}*5g5`-Q%8eX2McO1on zuy-hm4CKGsG;?&53i)BHLkM?p`}E?|4Hca~@lbIW$io9E3naMySa;yyU}epH*%p1> zwiqY*-~Bc;JnnqE?|kJ!|J($G%?=-LzkFyl$Z!!!R;-?~_;93Np}~}_XfvvzkQojC zu8rMoj*c3hTPYNRN(IY;AX`z?pNO0!5hNGXnNUbDE}Yh38lN#WUU0Nnq? zqusx0#wz#l#%GvyOyJKyx7$0PPPlc4yX%YX;hex*%fN+r7*0b@(9jWs0Pkt{+v~st zA5^Gd^os{^wue7;N-K5FsNHXiU*Qt$Ib#+dvK_LisKup>VaWz-(?Y7q7%jjl!$c@M z7i}fmTVqDAF6_y2<6k~xkzQquE6LAw z)a6b&vhQ3i>(fgzaf#Ex>og&(dKjio%X<6whx2jq6Z85Aldzj7WYQTmw0jA9JySGzHzw_SX zrKP0>KVE-d_7va1QVlQ5k4EEKs0atyGMx@sp#fN-!3e|7n=wcbaXz}Qhq(R1iyI=m(yi<6+hD5Xr7ATlA4#3ORBv6(nKJ6n5uKOg}y zP+;4*a+gRU>;s-88Uhj56x5wPqZ!>xI5;?*?%C11PkEJIZbU1XS3_7!F_c2>R}b8M zY7yc16X3u|MGUf_ky1li5F?#7Dmp7#&GBmFng5xu*TZgx8f*G_wI?*<$e{%WPhDM( z9xuso1MI{2%hb)6JeNO!OhxFGpW^NHP8{UWdBXd=w(eWc!zelv0swugP@+MgU{G>*YMJ)q|_kZ z6*i&Q0lfQ2$3P^@sl367=CzRavsR>>W{2=?#-#)dr4%3*k|Yo*C)MH%YmiFu-3&sv z`IoLjEiWdzUj&Z>Z$7UzJmuXV42vWjRd-WlR|kiMQC*_GKUIN`n?{fr{EZ-arv7Pb z7qc`%rZ_>pT)Eo;*A}Y*x+_XdF(N9}pu3(%}Ys&)sGymPJ{4x#QG+J!M|* z&n`<@rN=T@RkxIy${4&Cmoa=$*+=)|$<;*IUO673c%zZRaC% z0;OPtmSF$_gG&Cu&JO+$vu&^YqR4Ziz}JHFe#&Q1xk_GN7MG>d!KU~h8y>s$CW6%_ z`~C~F;q$*}9LDzc1g=-E#FUhgR9l2%G_CR^D6!$#*pL+P|hF zpxK!@1;Yb7bhl@#k=w%wFd&cPrDzR-le*3%7*z3I z=yv1)EIU|%Nw~Lh7<(B(Y7n)px>&brc4I;Pdamr4t$EF5uPBltrvEQ7 zX!}M}&icP0&1ygEdJ0unH#5pCFuME4rpG(}<(KucL-Vv1xAE$&D&oMtFU8OBO(LbQ zs?+s2-XieCW53Qhu!O@RDSgpFPV=|+#Mek(|4K8QCU_P%w<+KF9sKXwo#zuORo{{J zZxG#@y1OHkLQry=?0Wm5Pg*}&Im}*;Spy!p3VP=k^+T7Jb%5c-2$#Tt*ktO6#+H`8 z?|A&pqOGsp^QX;yslgksM9Z1tHv%jue0*Bg^|H?><9!VF9~2N5J{N8@-O%vxjY8>% zs-s8ygzfQ@jn4LN_oIcmDUqjRDv^N=!%wlEy{l#?D~+Gt(u^L`@=77EbL#5bclMb% z*^?HKZ|naG)sI>T48qol16&f9&HM+7a>LeQSUD5>iZUoms5s?73pTb(SI<`mH$KLt zPRIAo_?O;(*R+(qO_kLW%z21mLH5i1p0})RdAuO1oH6P=W$KhsSP-zBYieoM2E6!K zWh1VG!Gi5Dm@L>hO?IoOR|QHxtE#r5hbj82nm1w;8c8&ZB6~2YOJrjgoDfz@S_5GP z6IRRig)39x24Qy?V9*g(U_b&HBJRq8A*HSo%vB0A!UyPD5w-7uc#Q8ffqfX1Pr5+vU1bn!a~A8 zYwv#z`%v?A)@`)mGRBs(P(}Jyz(7A7;M^bKKKIW}qG^TAt&Myt$oO9PIMNR$hEuzR zL0FJN-4xN6+8h+0PdC*0X{M?d?54qNo~j_d_7q&uAAvzyTiX)VFPr#n!)EJvxt`zo zl1@37KiH!^UMYunD_sv7uIJc}QQ<~%)_(P3#gpT88O`ut?jaNOK@T^D*>!mrE&a6PU#48eEp_K-*|Leo=YdQP~jYHGCZ3n;;Dcuz30M z+r#e9k^53QLB+Ib*pt`YlCXQ$C>tUpEWS815vVu0AgYDBXPOvnX3S_*dV zXu-tV``vze#!NFSIvHux2}q((F#f` z;G)B#!?J>`N#sgrM|Q6m31b=4W4>#!FlMl9@JfLK@c$`$EA8?9hUtJs^(Lq94Ip`} zNBO6LYG!7p%bd1ip|h}%z0v7gbw3g(x#`t88u!v1aMY|I=wbJC{Mec` z<&c?USRj|J4Rqn+QG4MoEh%0myW++AVzTT(UoIsA32{tVYk)`+&dnJqYvz85{#;Z33WomE41iSNdz`Li0VwIr8_3!UQrrON>wb-Q^rQ92iG~3iIuhQ$oSwa& zJ|C}*Tb5atzh+=u)e}U7?xvaZH{qFB$Dz?u8l4XydDnR2XCkx0%TfP%>|NCl3dHd^ z2o5zN24j%F^n#k~w-3n$FVOA+Va>KbA4I^=2X7b$mF}7!uRp=&2RvFo-x$3Rj7z~b zcN`hq@1OZ0K_B;^W?*9Dy9vH+f6p$;`g+o&(JxftIT?apo1m`Sa-%_jl8H-AyOXz> zNM%~#pD)2V!~6FW!FPj}4m#GQosM#8Ng~ub4u4d> zy5T)^K7;EWFh(EEFO`yRS03C&6}i387)+0HTLl# z5%f46*!d%n%kNCqX^3^SP}Ls@pxxoDxpK~S6F8Bp)~T&MJxA$AUFjlKG4>3}E>$s_ z1-TAH-FSm?vvvG8%6AU{}Wpy-{H1p_X23GcfTxyCH=T&dAv_O zPJ|^fjL_dGOGAx~zi?y`Al4vWiUd6WGNSdEsKOvDRte;|&y`MONRf%;q2_u^P3CCK zyT2CMXhI6Ii_BbHaHFMg^E{B|>zFD0?@hQ#Fgmu&a-0@B?`V?c;Mwd0U>>u|3x+)3 zb_0Rsa7(@WJho-~#j}q){;F@i7MWGT<6hun_hRXWB>L5}IWeL_DdcOE2d>)1ifxVX z!$EOker%R8KyV*Xx(jLoZYs|xa!8(_`^}Sq--Xm>NGA|=t313cysHslq@>BzBI>;z ztoVPY!+OPL9<~ygqAFoyI|oNUQaZ`8@hJ5V-1DbGyu6_zZoUR~**UVjDZx;;tuc*~ z)b9!LW`3q*5^{cTGqN)djZUk+4#PL?9^#7))2>PHd<%Rj0w3O9Edji;jaTqYCvv@o zMVm3@ErU$_XtxszwFQgn!(KflyWknhiSY7T5JxyGmCrFbLc3mehbaU7co2L4gIQ)D zy8qXR{LHNTyw)n$GnT}R#zq;8DrJUD6s8a{9$iq>2hjw487B%?w3EF~dt9~aE=M#M!gqeYN9-tUQlEswV)A$hm zaC4NbP+GemzJCGWm?X$I4c5MM2|db^s34!tU|C9U_=JUT%EMZ@#>wD*=giyB+ z;Zl9bYq=`+6q);; zBO>1$N8OucxIY256k)FFQ(`t@04MkrDF;@3Z z*;LXSb&C@mn$hCGEn+3(MSo~f15L_h#O5U~_r2e#e(9M8|M6aZk1AnhO0xX=ou{iA zfrEkwV(MZFD+sV8?a~;o*jTUA2cYX&YBsO4xU}{3`uqOU!DNU0tWS*&2SugmsDQ6<|4KL_g%+NuvfsD(IBv);3N&@N#(V zeNHRN^KAwr@6#IpYPPT(wBJAPi;8;p3p(CcJyem3^6?6nE#_b}tmGAO*!(F7AIYe4 za+1bFCOcYBO5?|FosNQmmCYo5#$H(jeE{vg(IwFkA!kMEnBj|f^UE`KP|HtvkTOiM zZjMB6YYVl9DL2RV_C%a4X?L3tQnnnifBE(CKQe_f2k=I^56eFVZ)clpaf{24qB0vI z`s_$d0;EI@&STlfeq9{bPjTNKFJA>xium2DydEUJGESoWCq~SiZ8ZlzHM6YNY`i`^ zR9zM1t<b| z0VpgXNVU(u^0GG}64opREK5aZhl$mb2~P%QEj9j#X;(_+Mn39>8ZFgFo{SQb+E;n* zQ@H<8^b-z3TQWBP?EW5>vkOcn`;+*F75Dk`)fC6sdi&j7*VFo0z>OaCQIiF+mmfYM zqnX!!|yC#`>ZJhJ%C|f)vMKH+(?$d(=hZ)1Smu@nA zYEAqh|(lj@U?8k#U0~J+UaFDr9t=*zm?_0CkG8GMf)3(SNKb5%n zJ#$Hz12G8Yi>r=R_BA5)yIMQ6gp(k-9ujRQGSY-?u{rKD*XvD21f{t`GNjIY+w?-~ zY`(DdGnS^A6E~Qa*MOG*$|myV1r_gi5y5u6Ie^0ITA^Xn3Ozd$40!fBX7WP#*+Ovo zp{D(`ZR~kOR^;+(?ux6s$-!dXD-bMJyi8)#Z8}w#DRgco>Jgt5)zj9~FNhEk#P@ra z#|Nedn+&@Ngx!Bk)lb5|)P08i7zzWA0~v)+p!gVUTeA@@4(%J`I2)d{Uv)ZOLcxke zSyn`xu)zDR#z+wR9skpJ9#a0!+8}*;xT1ecFA1b3+4R~>tog!`ogCe9q|gh@pVd`= zdx|7mPS($cX3S)rZ;wCPwc7|9`fVX7Dk+IG$pFl~OeyF5-Yl^QQe_G(@%$dw$YH4m z9s(nKmo0lMw$xz&cSp$m=nvc%4uVP?5uC!HV%i_^@y`*D-9`t(73n^Q75+upj4w^9 z!u#X3R#!7Xn%sn=yzlu3u(};;5GS(X-uu4>PTqHK!gp(~_U5L?P^AfFN41bzO-Hec ztpi48%Pnl2Q0%nMH+&Ehx-_aHIsvn3$1;%%z0%JD1EhZL z|2l*Jw@l@HUtgAVCJJ1+azQXQY?TKZ5*Fo95v{BVOSn5;%7_J*wvaDjr7e$kQ@o@s zX7QY}KWysu=Jh{yuh;PXy0*3upUw!p;l$9ay4uM9&VW*fcj*(9+{POBUj4hb^MfQYHyCv*hoV0x*<939u4RmB-`8D0EH%- zWX~IX9`fcURT8?{Ny&%1R{1zA9#&DowDQY*toq--e}Qj<90AV0ey@X|d#=2@r#$FG z-snZesL^_@bHDH0KlFJU_ShKqz3&Yiriwq7&;o^#x4{GMLR4CE# zuB6~H>jMv8AW1V^{7Lbx?dX7ApH3bvo3Y|eQf4T!B@tN1ltU(tNQkcEY!Dz{N=L8= z2NtpawDRWA-FX82=56LL5bIjg+>fq^EG#V862|WC1OOL)@WTYemwCG)-D>0MBk?(& zxcJ0k{ffeM>*AT8p=lB#1;fEFNU9YYYUGtP1yjX_j)kJcoA(!H{65!Ui-nru`+I&~ zhZXqMCN=g9HRiM=h4N`TUUujxJv^|mu>#7^#Ri~nyv**4+_j?q74jp4ePgW#=&`79 zv-37bqKZ<$Pkr*aMG|*(AGpQ5k32yIb|y%Yd_t2XNglWA--tY zrU-hpeP5B%VlzgFObtv(Qe%JMzLGmN!Y&6|rya4Jl835#b4e+lJt`P}Ycd3jR3zw}WgOlV+RUI3X z6w3i&B9+-(y9s0LSMp>DjK$6sLc^*(ca9P;XC&(++LuF2NSy4#B{;GEz01rO^u#od z$dc;;qyMa`2AGD}oV!(aL<67fj!STXDW(kCF|-@%eL2eT_6z`$N72{ksW+hoq#@A# zEfiYtFmCC>x8XI{4ei=)n^LKPCg~aIN!LK(gf`7ggYdO$?=pw4kx$LUVM04QjKd~S zT0Wb06D`3BqKJKk_b!x$mxKO}(RWIfjNXbWT&nDW&!akCvB1IGY>AeHoXUp(E!5(- zX~NEG(K zUVB-Vnt=!dYeZJ}w7gQ|-FfiK1d9#NRxg<`tiL-6}+J@Y-`QE|;dh z_pVti2`l?IjlOPfT!u0MHm1Xy#-rz+3!8S6Q;PiKF2}Jb2Z4u+1`%;vkE~r+AqO0{ zesTrdD=)g!;YNSyG@MEs+wJ^MbIi&_0D85_Jh1!qs9U7f`|9(XNx=5PsuGu^ZR2C@ z&im{fQj$qQfi3&grwarZU6WN(na2>x%AZl{+=*cbYRv@VlH*|F1PTe7671>HJV!T zwyAp+qIo-b;$;84RpB!GNPwqa8v#U}cmPiOO80E$BjuATmXD^KDvO?MxJX zJ#eh2V0dSq@g7EX9E^?!ash;;20&r9r0_ki)Ajp3fPQX|_jtO|xtg1m^>Q#U@TiAD z%ci+#LtRfDlq%SV3kyQaXvGL0>VxA(OhuK|ra8VuMx!-!{xTpHEQK5puo#t?iP?86 zfHO}NgM5S+ME@QV%?cSsM;At*zM+o5qr>eD>Q~$DVch*#aKpI`Io4$_4>)5$5?`zy zQ`=HTaS1gZA6J}fbVu{zC6-LF;2S#>=B!93BQBY6~oNEao;H+mwdIx zcQOCMC4J!2*Vxi6_kF+lKw9Jwfxj*alNj;9o?VU#Y9)cNB~3S=&+dI0oO^b>-ESmOo<-+drP}#YH}z_<<71dVvlhgXveoiXlXM zXAvhbY@4ug~8w5245o2#W=GRzh%}?<*@Znrvy*@LEv(7gV|=M zKxy-D+W%Y>NC*Ot82Nakm8PQki5OXm)d59^GQ(!U1v_3MLPElPps*b?fxB_MrUA&u zYiQ$uJ;B4hQQ)Fi!JKBU)(W@RBn1Mha9$q;qXTX%C1j2rIr52M z16GcE4|uVNjM=C^C!s%TbC5I=^h&bx^OaSUl-6DE);*_&_bqeb{65upuR3-Mb8@P^ zwA#4ape2`hl;hwQkFX|KHOK{c;m^M?q0kTnMG0!lwHnJMu;f|OLOi5Gii?YjFIUj>v=fARzgTha z76Wt6He3z8%D=N?AsiM}Wlua>cOd%h93d9M0ixS7=7aU#gm0N8EU3rhDumZ&1ohFX zIWVBaTYcsa(sRr~KF8U~GYDBq>Bat4f&OEe=7Yr}ZVcv(0Pj;litl>DoQ-?l{OU~c~ zBUX0rhmnUC5~j}{TW3eWG%*l`F=6{lq!b?uv8lertI2ccylxLDy5_`MYNdx4>e8p! z5}<}p?p!N&>$78h$co#3|BQfR4N)jwJStr|@%RBfV@S;BPu}o6H&#gbpv9UtJ8#3o z!^@iv$j@!5UpG+4lZrQonc?}pB&?u?A^l`jzISY^GIiP|qobpq4l51+I_vA}-*)dW zwma`r{~IKPARxA&Qgzy$#rh;;9__;X33yq?ll$rjxV`e*^r~_&7T@d1SS-_*n((|;E;3-S~@e_|#5wCNnt4L8lZ*vn9 zXL$vG>!;h3F+Qk|Z?QhRUMXbsa`lvbC>7=a^cD0~p+c&1{=?x-n>U~(Tm#jdSfC^} zq6JW@$D1RrU6+s4rG9hTTcp7?`@xhFL8RHkz=1qc?0^x$`XDnmcbq78(DxKb9Dxrj zi(O5d2IYSV;5PNlx+fgUGGEU$UzigYx^L2g! zzZ*+MOzKk$cJj9vSZyC_?)KRXDh_`A9Bheixg6heStRj%oYE1q{HB z>s=EoX_||4b&l>`LioS%N*LBb5HZlah?n)ix0eUMuJe2a^PfBXysWmHqbeh!91;Cc zDo&!$aBbeA3Fl&%eWqCA@@>V;!VRX3Np2uU7(@B8qBelTX?%ye`# z<#tj6c&{E77K7tRx0E)3Eu!8sBYh#kZnf!TCsOpede@~@=pIMx%=F#_<~z&*a&TPn zmq|ss_~;7vyt-)jb(!Kizk})C=X&3KQjQE3vm8Fh@m(~8D-4WSVHh8`D4&Krfgc7j zuPfArv3ob{pn#b>E*cpW5i~cl%(CFoiqU^{DQ0Id=g9iSXZ%F>h&9?s_w>he02O=7 zR?2C5aXea_(pp_-XC3x%cgJ>+MU+)iw5Ef~BrDWC3AvU`O#~`^`I-~;`$xE?4i8P> zg$h58wJpoe)%P9dX%6jw@d}OWJAW^K+q_*c6d3sZ9i=>FA!PPF1IqRN?H(sT%s;%_ zkME-@#m^jd*1k#m3zI^nS@LmQA{$Zb2VSRL(X>#zTeauk9j3t`MSAtNq_3IL_ps}p z{d`?LX83NW6;YW&j6&4#qA?#NznScn_r+BS3a5sq_o$s;CBkUoeW#(4r;wz}EMo%H zNroTuhi3m()D_T!IN>_}E>nW4G=3acYgTeaSoc)(gxr3()SYIOJ5uAuM5Ga!691K3 zyiOIhWZ}IzP+iM=aOkw;>WG6}M)Pn%_GD2J2WY1XO|a_O`|~c6^armRsD3-sGeiAY zq8??db%x$=Pp3k4X2S_XDkJyo$N^jawXki!)zV#3F>t*R|DlQ%@h^1m4gKu{5|M6X zLcUdX_57kew294;9`{i$as7ROHMJGO%h2x>9E^#NBBEpzhliVTC^3<}9N7xyjy9CE z$5RyM(dp)Z*{u*#q0b{M><<^zPk|PvH4ds-dVkt+H90E?^}gy}ZLl75SKz$y0T8Tu zLuIH;8U74*FWk3$U$t3TNj@lJu+=@e+8v=Mdlb~E7d!z!6#My0+%>kLJ~BJvOK|;N zxRxfR|ITRWpu}$Y(`ozJ!P=Vs-2~&%FTSx7N3Lb`nfla&<+%KidH1C{e7D%;S~9|z zsM*%PR5=_?DtS7!gp=&n7R>esWlRL2WQb%IONM&Ciq~==TmG`%Y-1Y@Lb9!m-n#_3 zRy&V4E3x6}CQ;z-!f!{#`tZ-NL9v>l!r=vwgjE`%j>WWLD+p5kEMPFyh5VMiJ6R~9+Bgau#>V}N zj0e;rk1ZjmjO0t5rFPV8&>VKP0WYowvIq?}Nn0^f~Op+B)n&hx*8CS;j{wGS* zfJ=gqrAmljdtPLlv41{J`%x$m%Mkfl0~BCbJ^x7--5ODt-g=oZX7H;fE1_dJJ5s4a5*9*;+d{QB{>UPZ*$;jG@*Xub0(UCW{K zW+CkphPVA{`bz-x*iGP{OmT9ZyKssz(uL~^ZbHG<2_}BJ=~)EpkR;3?xy;Osj^cpB0p|{v9r!z)gwJEUUuui*|Grb+ zYJ6`CTT7l1jEc>TLsI>Y5H9-YL7is-GWTY?Xfhby&vm(AU?alPquv?Xt~n&9*AApx_8Hmy47wMvySki^RrX;uvE)wa^poyX)U^sfzf4=dnJ%Xmt_^0 zNYD{yo9qGOaGYjkilMfEmW3`C67NmCOCu9r)@hLVPccju`fp9_;eX)EqqmBFh&j8I z&DVKtl}Zi|bPUehv|9OmE{XjmMh%KbjzGM&SNSG^u3p@O-8a<_Q6&>ET)!eW2wFrG z<$+Dd_s*kgjw}5Z{%#7Q`0+mnz=I-vy)6(IfdD0^Ag!aL2fByzxk|HAy%cis!;UxB zqLPcQ_NNjp<8L8X?FkGuPnx~Sjo5UGRTzXd%#lRk?c3RR89g{_?CebbuOdI6sUghzHWf;z^urPt zH#_W|SmM_arE16KL`u>2w#hmni-~99JtRs=ie(AK0FL(!=eR`g>O?B_+iblrU)G zgdU`|)Adt>c`;RC@TWP3{?kA7KR?gD-Zp{>UMnjtG3D0Xfb+mO)e6Oac)!{w z-#aK-hY=nL>aq}eMK~OEa}R#qei=l3B2(GDA1z!Sv;23g85;1ky!aGq+o)RyNF1pU zAs!xgK>T_hfb+)>svd-J9#!SzhJKk%4&V7P_j4a8vgmkB(Z}o8DQ9znLNO{3%jhI) zzZL~RBrWXPTyJ+~8bcW}#w+S<6p-Z$ukz5{QHZmBs}6J>=C!e>J&DUqYs6sr6|sL` zseg$eCQ%%mS&=t}XJ zkQ{C^jo>u^5Uog5=x|qET00ibur{^mqc}BquM0;fIOIui_h^hkMYQO$D|;aqnKK8r zU);N+x1T{JWC5=FXvgp`?`&L!HI#-+vT{?1Galvllj7e znw9ekt@;l3fT2@ou7NKijj?dvliPGQM_3jeJsnPZcEJ@+O|HsqCEm}~+k0(1&4w<% z3wtM1;$wty3V9iL9Dllgej&R46OWua3&AD5jGb0AC=><(MhVv7Q!j)aj*K6+XCHBC}CdJ4~dXrCk@p+GR>?aGc&JBtxE-rk~t4*EsyH;eB| zwsg#QRVVdX_}ol5_SYDhj5wJH1s}bCxPO5bnKgGFHJQ!ZxS#uME&^$%6k=TgsrcFH z+^#0hqzd&Yx4X3~%OBJ=64%9)kEE;6C|a+oI$YPS`pHnwR+Q6;*{dvP5nqJ0yF4Ce zc673EQJThWUFJX%QIhO$=_|YxA#Ycq{pe$8vWj0yP{r$~pZXK86!3DVq_kOSJR@yd}iF^P{h$dqJj z_l_+9wBg2+>*%@LEpZ=*MW#u*wfmGAq5X~Hf)uk|X3}m7h9^soDn-7fx1QvpZkFQ9!NG# zQV7*#>gtQ8@Txs;tdH(Objf;(6K)6s6O?LZU7Y4~!=WXSZg~c&MI%H}0hNO&1hl#u zTZZVyN&wpINv|afp(29k0VQnHL*=BNLi)F4OvJy?y%CMxJ+MzZ^wN%FAf91mnvGm8 zs{wW^^ZMo4@$qq?pwJ6zBDhV0dXJM8^X#%#&Xm!T=Z#4!A`0?Mnc__%oWfcL?ORSZ zngsVb*?c|pWFuM><*!a*^pUvlJY=;kX61?7$cC~;yfDF6(X_HT`|0TkfycCzIv>!t zzZHG1Umgc`fk;$n=(1;wIZhtPz__t3xXJz#{uJFc;nFjW7{h~*WJ+JE&B(=7``9Se z+@!fM*BX(OZHA*wE5{dn7@UA>%r&R?v(ZPF#+*(`{fglb1(u8kxyYDFV%Xx^J_0+e ztG|{&64q&?YK0|G@k-TjfsYHBnUwlF6U7hYcG~=p5MmUa{7e1f&vbqX9%*2f9hX)K z-kh7NOD4=vGf)Rj9~3A!N%$xT41=_G889VB|mT7k{kkA9^}_O2WUpHFJ(drc;l zK@AaKffPGc1l){&#ydw)bF+y-#)t(jPEF5<^)^nmL$hV~^)s3!-%q1JU_xJh`<2#f zY|PHaru05#)Td5c-?!eQ40gJXY@#7;hMe(G@TU&zPET+dJ{nStK2scs;g^5q+;8-@ z^<3_`DiIups8Xk#3WLJBcM6}JD(C;PRq>|G|Dq3fnokP>Nux8tBR1v09j^q@FCmDj z5VO5FvvxVdhJO@5pm6aM51Xm`3l_S)3OG#)Ql-hm zVYSP0;XNl)z2=&LFiS9yEm}Y$F(4S( zPrAy@X*g@N)DvB_AQX>8+g)CmdbryB1}$BKF~!xgB3pQ@B{6t|4~Q`{^~46N^N5&s zLp>&PrdEozpQRcm@lAYYf@PCE_y%#ZKK%iUV`MQf4obesz^gL-#VppQ&QknpLOi!< z=xcvFl1y7i@gHP_16@7%eN2{%%ZU)5&}8{AI9v4#G5LpRUAzP~x^h_$-ZYZpZA1ZH zR5(K+=2&KcNpe=Ccs$DKh@pgly%;K|T_dISV=Yp;K)|(=y@kb|Tchqtx8}j>+1(r- z9v(xW#<{vev|){Mi|o0OQ$usRx%hN1u5rkAcsgcJ-%jvc^TLWhLk1yy zP)Yg4T&Gj>8F&S**|*%0MLR(+ycwY%2YwJX!BnnxY#L|p5{!TQqp*M|pGopO^NytU zlK6dO;u9Z1w#;LqUIJV{H(*yR1KezcJ*Iw#gCMW>_+nD*8955TUIT;0PAB>X+?)2r z2o^#~-eMee@?wqREzkL<1 zz($>REp`i+!c<&fTg`TMnLA)@Ox%%~J-V5lu&AH6Z2!C&JdrJ3qJ!BkjU5?gDjmF;nUxA&GSQ0(5EY)rgA3J0 zjsUULP6VA8enk8!Xj|1)WnG3So)jVu>8UlCafLd!i_^6lTQPa+f8WC<8+FPoO0E2? zRScK7RQ3A!Q6!KaEflW1+hmA{P}XmVm_X?%wDvjXmzf|~5f3naFlQ-R;3SU6!JI3M z!dTQVyN`bPFq*&c3ErkV$}7t&HHg~fwMRukI?<*Z8`g-Bwr|L9al=ro*2(@&W-o~W zmjprqV&<_sJI((YLqs&`#;wGzq@v*`GtoF4QT=KiMs^cXc-7?E$ zEo02YF;&4#a&;KU@36&aR}t~ z@UF1T+I)^1W48r~3*mF$_dw|MmyPokCE5ucd_v_2CR&V}+P41T{u7klk7z6zq1k0y zu)A`N%V#5pcfPm3f44p=@vW-{V$fS&`*aQfudGkwcWOYf^3Tyt`Qgo@r(?&(5aoJL zeY;}idR*fQk*%%0AQO37T{zWnu$x$4ZIQgq1gCImE7`Xw9?T~Lv8 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 - - 00.10 - - 0 - - - 1 - - - HG - - - This application was created with the official non-official SDK called PSL1GHT, for more information visit http://www.psl1ght.com/ . This is in no way associated with Sony Computer Entertainment Inc., please do not contact them for help, they will not be able to provide it. - - - 0 - - - 03.5500 - - - 63 - - - 279 - - - SACD Daemon - - - SACDDAE01 - - diff --git a/tools/sacd_daemon/src/exit_handler.c b/tools/sacd_daemon/src/exit_handler.c deleted file mode 100644 index 2da8019e..00000000 --- a/tools/sacd_daemon/src/exit_handler.c +++ /dev/null @@ -1,70 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include - -#include "rsxutil.h" -#include "exit_handler.h" - -static int receive_exit_request = 0; - -static void sysutil_exit_callback(u64 status, u64 param, void *usrdata) -{ - switch (status) - { - case SYSUTIL_EXIT_GAME: - receive_exit_request = 1; - break; - case SYSUTIL_DRAW_BEGIN: - case SYSUTIL_DRAW_END: - break; - default: - break; - } -} - -static void program_exit_callback() -{ - sysUtilUnregisterCallback(SYSUTIL_EVENT_SLOT0); - - gcmSetWaitFlip(context); - rsxFinish(context, 1); -} - -int initialize_exit_handlers() -{ - int ret; - - ret = atexit(program_exit_callback); - if (ret != 0) - return ret; - - ret = sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0, sysutil_exit_callback, NULL); - if (ret != 0) - return ret; - - return 0; -} - -int user_requested_exit() -{ - return receive_exit_request; -} diff --git a/tools/sacd_daemon/src/exit_handler.h b/tools/sacd_daemon/src/exit_handler.h deleted file mode 100644 index dcc52ecd..00000000 --- a/tools/sacd_daemon/src/exit_handler.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef _EXIT_HANDLER_H__ -#define _EXIT_HANDLER_H__ - -int initialize_exit_handlers(); -int user_requested_exit(); - -#endif /* _EXIT_HANDLER_H__ */ diff --git a/tools/sacd_daemon/src/main.c b/tools/sacd_daemon/src/main.c deleted file mode 100644 index dd0fb7f2..00000000 --- a/tools/sacd_daemon/src/main.c +++ /dev/null @@ -1,408 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "rsxutil.h" -#include "exit_handler.h" -#include "server.h" -#ifdef ENABLE_LOGGING -#include "output_device.h" -#endif - -#include -#include - -#define MAX_PHYSICAL_SPU 6 -#define MAX_RAW_SPU 1 - -static int dialog_action = 0; -static int bd_contains_sacd_disc = -1; // information about the current disc -static int bd_disc_changed = -1; // when a disc has changed this is set to zero -static int loaded_modules = 0; - -static int load_modules(void) -{ - int ret; - - ret = sysModuleLoad(SYSMODULE_FS); - if (ret != 0) - return ret; - else - loaded_modules |= 1; - - ret = sysModuleLoad(SYSMODULE_IO); - if (ret != 0) - return ret; - else - loaded_modules |= 2; - - ret = sysModuleLoad(SYSMODULE_GCM_SYS); - if (ret != 0) - return ret; - else - loaded_modules |= 4; - - return ret; -} - -static int unload_modules(void) -{ - if (loaded_modules & 4) - sysModuleUnload(SYSMODULE_GCM_SYS); - - if (loaded_modules & 2) - sysModuleUnload(SYSMODULE_IO); - - if (loaded_modules & 1) - sysModuleUnload(SYSMODULE_FS); - - return 0; -} - -int file_simple_save(const char *filePath, void *buf, unsigned int fileSize) -{ - int ret; - int fd; - uint64_t writelen; - - if (buf == NULL) - { - LOG(lm_main, LOG_ERROR, ("buffer is null\n")); - } - - ret = sysFsOpen(filePath, SYS_O_WRONLY | SYS_O_CREAT | SYS_O_TRUNC, &fd, NULL, 0); - if ((ret != 0)) // && (ret != EPERM) ){ - { - LOG(lm_main, LOG_ERROR, ("file %s open error : 0x%x\n", filePath, ret)); - return -1; - } - - ret = sysFsWrite(fd, buf, fileSize, &writelen); - if (ret != 0 || fileSize != writelen) - { - LOG(lm_main, LOG_ERROR, ("file %s read error : 0x%x\n", filePath, ret)); - sysFsClose(fd); - return -1; - } - - ret = sysFsClose(fd); - if (ret != 0) - { - LOG(lm_main, LOG_ERROR, ("file %s close error : 0x%x\n", filePath, ret)); - return -1; - } - - return 0; -} - -static void dialog_handler(msgButton button, void *usrData) -{ - switch (button) - { - case MSG_DIALOG_BTN_OK: - dialog_action = 1; - break; - case MSG_DIALOG_BTN_NO: - case MSG_DIALOG_BTN_ESCAPE: - dialog_action = 2; - break; - case MSG_DIALOG_BTN_NONE: - dialog_action = -1; - break; - default: - break; - } -} - -int patch_lv1_ss_services(void) -{ - install_new_poke(); - - // Try to map lv1 - if (!map_lv1()) - { - remove_new_poke(); - return -1; - } - - lv1poke(0x0016f3b8, 0x7f83e37860000000ULL); // 0x7f83e378f8010098ULL - lv1poke(0x0016f3dc, 0x7f85e37838600001ULL); // 0x7f85e3784bfff0e5ULL - lv1poke(0x0016f454, 0x7f84e3783be00001ULL); // 0x7f84e37838a10070ULL - lv1poke(0x0016f45c, 0x9be1007038600000ULL); // 0x9be1007048005fa5ULL - - remove_new_poke(); - - // unmap lv1 - unmap_lv1(); - - return 0; -} - -int unpatch_lv1_ss_services(void) -{ - install_new_poke(); - - // Try to map lv1 - if (!map_lv1()) - { - remove_new_poke(); - return -1; - } - - lv1poke(0x0016f3b8, 0x7f83e378f8010098ULL); - lv1poke(0x0016f3dc, 0x7f85e3784bfff0e5ULL); - lv1poke(0x0016f454, 0x7f84e37838a10070ULL); - lv1poke(0x0016f45c, 0x9be1007048005fa5ULL); - - remove_new_poke(); - - // unmap lv1 - unmap_lv1(); - - return 0; -} - -int patch_syscall_864(void) -{ - const uint64_t addr = 0x80000000002D7820ULL; // 3.55 addr location - uint8_t access_rights = lv2peek(addr) >> 56; - if (access_rights == 0x20) - { - lv2poke(addr, (uint64_t) 0x40 << 56); - } - else if (access_rights != 0x40) - { - return -1; - } - return 0; -} - -static void bd_eject_disc_callback(void) -{ - bd_contains_sacd_disc = -1; - bd_disc_changed = -1; -} - -static void bd_insert_disc_callback(uint32_t disc_type, char *title_id) -{ - bd_disc_changed = 1; - - if (disc_type == SYS_DISCTYPE_PS3) - { - // cannot do anything with a PS3 disc.. - bd_contains_sacd_disc = 0; - } - else - { - // unknown disc - bd_contains_sacd_disc = 1; - } -} - -void main_loop(void) -{ - int client_connected; - msgType dialog_type; - char *message = (char *) malloc(512); - - // did the disc change? - if (bd_contains_sacd_disc && bd_disc_changed) - { - bd_contains_sacd_disc = 0; - } - - // by default we have no user controls - dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_DISABLE_CANCEL_ON); - - if (!bd_contains_sacd_disc) - { - union net_ctl_info info; - - if(netCtlGetInfo(NET_CTL_INFO_IP_ADDRESS, &info) == 0) - { - sprintf(message, " SACD Daemon %s\n\n" - "Status: Active\n" - "IP Address: %s (port 2002)\n" - "Client: %s\n" - "Disc: %s", - SACD_RIPPER_VERSION_STRING, info.ip_address, - (is_client_connected() ? "connected" : "none"), - (bd_disc_changed == -1 ? "empty" : "inserted")); - } - else - { - sprintf(message, "No active network connection was detected.\n\nPress OK to refresh."); - dialog_type |= MSG_DIALOG_BTN_TYPE_OK; - } - } - - msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL); - - dialog_action = 0; - bd_disc_changed = 0; - client_connected = is_client_connected(); - while (!dialog_action && !user_requested_exit() && bd_disc_changed == 0 && client_connected == is_client_connected()) - { - sysUtilCheckCallback(); - flip(); - } - msgDialogAbort(); - - free(message); -} - -int main(int argc, char *argv[]) -{ - int ret; - void *host_addr = memalign(1024 * 1024, HOST_SIZE); - msgType dialog_type; - sys_ppu_thread_t id; // start server thread - - load_modules(); - - init_logging(); - - netInitialize(); - netCtlInit(); - - // Initialize SPUs - LOG(lm_main, LOG_DEBUG, ("Initializing SPUs\n")); - ret = sysSpuInitialize(MAX_PHYSICAL_SPU, MAX_RAW_SPU); - if (ret != 0) - { - LOG(lm_main, LOG_ERROR, ("sysSpuInitialize failed: %d\n", ret)); - goto quit; - } - - init_screen(host_addr, HOST_SIZE); - ioPadInit(7); - - ret = initialize_exit_handlers(); - if (ret != 0) - goto quit; - - // remove patch protection - remove_protection(); - - ret = patch_lv1_ss_services(); - if (ret < 0) - { - dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON); - msgDialogOpen2(dialog_type, "ERROR: Couldn't patch lv1 services, returning to the XMB.\nMake sure you are running a firmware like 'kmeaw' which allows patching!", dialog_handler, NULL, NULL); - - dialog_action = 0; - while (!dialog_action && !user_requested_exit()) - { - sysUtilCheckCallback(); - flip(); - } - msgDialogAbort(); - - goto quit; - } - - // patch syscall 864 to allow drive re-init - ret = patch_syscall_864(); - if (ret < 0) - { - dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON); - msgDialogOpen2(dialog_type, "ERROR: Couldn't patch syscall 864, returning to the XMB.\nMake sure you are running a firmware like 'kmeaw' which allows patching!", dialog_handler, NULL, NULL); - - dialog_action = 0; - while (!dialog_action && !user_requested_exit()) - { - sysUtilCheckCallback(); - flip(); - } - msgDialogAbort(); - - goto quit; - } - - // reset & re-authenticate the BD drive - sys_storage_reset_bd(); - sys_storage_authenticate_bd(); - - ret = sysDiscRegisterDiscChangeCallback(&bd_eject_disc_callback, &bd_insert_disc_callback); - -#ifdef ENABLE_LOGGING - // poll for an output_device - poll_output_devices(); - - if (output_device) - { - char file_path[100]; - sprintf(file_path, "%s/daemon_log.txt", output_device); - set_log_file(file_path); - } -#endif - - sysThreadCreate(&id, listener_thread, NULL, 1500, 0x400, 0, "listener"); - - while (1) - { - // main loop - main_loop(); - - // break out of the loop when requested - if (user_requested_exit()) - break; - } - - ret = sysDiscUnregisterDiscChangeCallback(); - - quit: - - unpatch_lv1_ss_services(); - - destroy_logging(); - netDeinitialize(); - unload_modules(); - - free(host_addr); - - return 0; -} diff --git a/tools/sacd_daemon/src/output_device.c b/tools/sacd_daemon/src/output_device.c deleted file mode 100644 index 718a394f..00000000 --- a/tools/sacd_daemon/src/output_device.c +++ /dev/null @@ -1,97 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include - -#include "output_device.h" - -int output_device_changed = -1; -char *output_device = 0; -double output_device_space = 0; -uint64_t output_device_sectors = 0; - -int poll_output_devices(void) -{ - static const char *device_list[11] = { - "/dev_usb000", "/dev_usb001", "/dev_usb002", "/dev_usb003", - "/dev_usb004", "/dev_usb005", "/dev_usb006", "/dev_usb007", - "/dev_cf", "/dev_sd", "/dev_ms" - }; - static int old_devices; - uint32_t current_devices = 0; - char *largest_device = 0; - double largest_device_space = 0; - uint64_t largest_device_sectors = 0; - int i; - - for (i = 0; i < 11; i++) - { - sysFSStat fstatus; - if (sysFsStat(device_list[i], &fstatus) == 0) - { - current_devices |= 1 << i; - } - else - { - current_devices &= ~(1 << i); - } - } - - if (old_devices != current_devices) - { - for (i = 0; i < 11; i++) - { - if ((current_devices >> i) & 1) - { - double free_disk_space; - uint32_t block_size; - uint64_t free_block_count; - - sysFsGetFreeSize(device_list[i], &block_size, &free_block_count); - free_disk_space = (((uint64_t) block_size * free_block_count)); - free_disk_space = free_disk_space / 1073741824.00; // convert to GB - - if (free_disk_space > largest_device_space) - { - largest_device = (char *) device_list[i]; - largest_device_space = free_disk_space; - largest_device_sectors = (((uint64_t) block_size * free_block_count)) / 2048; - } - } - } - } - - if (old_devices != current_devices) - { - old_devices = current_devices; - if (output_device != largest_device) - { - output_device = largest_device; - output_device_space = largest_device_space; - output_device_sectors = largest_device_sectors; - output_device_changed = 1; - return 1; - } - } - - output_device_changed = 0; - return 0; -} diff --git a/tools/sacd_daemon/src/output_device.h b/tools/sacd_daemon/src/output_device.h deleted file mode 100644 index 4fae6967..00000000 --- a/tools/sacd_daemon/src/output_device.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __OUTPUT_DEVICE_H__ -#define __OUTPUT_DEVICE_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern char *output_device; -extern double output_device_space; -extern int output_device_changed; -extern uint64_t output_device_sectors; - -int poll_output_devices(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/sacd_daemon/src/rsxutil.c b/tools/sacd_daemon/src/rsxutil.c deleted file mode 100644 index 0002189e..00000000 --- a/tools/sacd_daemon/src/rsxutil.c +++ /dev/null @@ -1,173 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include - -#include "rsxutil.h" - -#define GCM_LABEL_INDEX 255 - -videoResolution res; -gcmContextData *context = NULL; - -u32 curr_fb = 0; -u32 first_fb = 1; - -u32 display_width; -u32 display_height; - -u32 depth_pitch; -u32 depth_offset; -u32 *depth_buffer; - -u32 color_pitch; -u32 color_offset[2]; -u32 *color_buffer[2]; - -static u32 sLabelVal = 1; - -static void wait_finish() -{ - rsxSetWriteBackendLabel(context, GCM_LABEL_INDEX, sLabelVal); - - rsxFlushBuffer(context); - - while (*(vu32 *) gcmGetLabelAddress(GCM_LABEL_INDEX) != sLabelVal) - usleep(30); - - ++sLabelVal; -} - -static void wait_rsx_idle() -{ - rsxSetWriteBackendLabel(context, GCM_LABEL_INDEX, sLabelVal); - rsxSetWaitLabel(context, GCM_LABEL_INDEX, sLabelVal); - - ++sLabelVal; - - wait_finish(); -} - -void set_render_target(u32 index) -{ - gcmSurface sf; - - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; - sf.colorLocation[0] = GCM_LOCATION_RSX; - sf.colorOffset[0] = color_offset[index]; - sf.colorPitch[0] = color_pitch; - - sf.colorLocation[1] = GCM_LOCATION_RSX; - sf.colorLocation[2] = GCM_LOCATION_RSX; - sf.colorLocation[3] = GCM_LOCATION_RSX; - sf.colorOffset[1] = 0; - sf.colorOffset[2] = 0; - sf.colorOffset[3] = 0; - sf.colorPitch[1] = 64; - sf.colorPitch[2] = 64; - sf.colorPitch[3] = 64; - - sf.depthFormat = GCM_TF_ZETA_Z16; - sf.depthLocation = GCM_LOCATION_RSX; - sf.depthOffset = depth_offset; - sf.depthPitch = depth_pitch; - - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; - - sf.width = display_width; - sf.height = display_height; - sf.x = 0; - sf.y = 0; - - rsxSetSurface(context, &sf); -} - -void init_screen(void *host_addr, u32 size) -{ - context = rsxInit(CB_SIZE, size, host_addr); - - videoState state; - videoGetState(0, 0, &state); - - videoGetResolution(state.displayMode.resolution, &res); - - videoConfiguration vconfig; - memset(&vconfig, 0, sizeof(videoConfiguration)); - - vconfig.resolution = state.displayMode.resolution; - vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; - vconfig.pitch = res.width * sizeof(u32); - - wait_rsx_idle(); - - videoConfigure(0, &vconfig, NULL, 0); - videoGetState(0, 0, &state); - - gcmSetFlipMode(GCM_FLIP_VSYNC); - - display_width = res.width; - display_height = res.height; - - color_pitch = display_width * sizeof(u32); - color_buffer[0] = (u32 *) rsxMemalign(64, (display_height * color_pitch)); - color_buffer[1] = (u32 *) rsxMemalign(64, (display_height * color_pitch)); - - rsxAddressToOffset(color_buffer[0], &color_offset[0]); - rsxAddressToOffset(color_buffer[1], &color_offset[1]); - - gcmSetDisplayBuffer(0, color_offset[0], color_pitch, display_width, display_height); - gcmSetDisplayBuffer(1, color_offset[1], color_pitch, display_width, display_height); - - depth_pitch = display_width * sizeof(u32); - depth_buffer = (u32 *) rsxMemalign(64, (display_height * depth_pitch) * 2); - rsxAddressToOffset(depth_buffer, &depth_offset); -} - -void waitflip() -{ - while (gcmGetFlipStatus() != 0) - usleep(200); - gcmResetFlipStatus(); -} - -void flip() -{ - if (!first_fb) - waitflip(); - else - gcmResetFlipStatus(); - - gcmSetFlip(context, curr_fb); - rsxFlushBuffer(context); - - gcmSetWaitFlip(context); - - curr_fb ^= 1; - set_render_target(curr_fb); - - first_fb = 0; -} diff --git a/tools/sacd_daemon/src/rsxutil.h b/tools/sacd_daemon/src/rsxutil.h deleted file mode 100644 index 9b287a74..00000000 --- a/tools/sacd_daemon/src/rsxutil.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __RSXUTIL_H__ -#define __RSXUTIL_H__ - -#include -#include - -#define CB_SIZE 0x100000 -#define HOST_SIZE (32 * 1024 * 1024) - -#ifdef __cplusplus -extern "C" { -#endif - -extern gcmContextData *context; -extern u32 display_width; -extern u32 display_height; -extern u32 curr_fb; - -void set_render_target(u32 index); -void init_screen(void *host_addr, u32 size); -void waitflip(); -void flip(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tools/sacd_daemon/src/server.c b/tools/sacd_daemon/src/server.c deleted file mode 100644 index b17b6277..00000000 --- a/tools/sacd_daemon/src/server.c +++ /dev/null @@ -1,278 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "server.h" -#include "exit_handler.h" - -int closesocket(int socket); - -static int client_connected = 0; - -int is_client_connected(void) -{ - return client_connected; -} - -static void client_thread(void *userdata) -{ - p_socket client = (p_socket) userdata; - ServerRequest request; - ServerResponse response; - uint8_t zero = 0; - uint8_t *output_buf = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); - pb_istream_t input = pb_istream_from_socket(client); - pb_ostream_t output = pb_ostream_from_buffer(output_buf, MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); - sacd_reader_t *sacd_reader = 0; - scarletbook_handle_t *handle = 0; - int non_encrypted_disc = 0; - int checked_for_non_encrypted_disc = 0; - uint32_t encrypted_start_1 = 0; - uint32_t encrypted_start_2 = 0; - uint32_t encrypted_end_1 = 0; - uint32_t encrypted_end_2 = 0; - uint32_t block_size = 0; - uint32_t end_lsn = 0; - - client_connected = 1; - - response.data.bytes = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE); - - for (;;) - { - if (!pb_decode(&input, ServerRequest_fields, &request)) - { - break; - } - - response.has_data = false; - response.data.size = 0; - response.result = -1; - - switch(request.type) - { - case ServerRequest_Type_DISC_READ: - { - response.type = ServerResponse_Type_DISC_READ; - if (handle && sacd_reader) - { - int encrypted = 0; - end_lsn = request.sector_offset + request.sector_count; - - // check what block ranges are encrypted.. - if (request.sector_offset < encrypted_start_1) - { - block_size = min(encrypted_start_1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); - encrypted = 0; - } - else if (request.sector_offset >= encrypted_start_1 && request.sector_offset <= encrypted_end_1) - { - block_size = min(encrypted_end_1 + 1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); - encrypted = 1; - } - else if (request.sector_offset > encrypted_end_1 && request.sector_offset < encrypted_start_2) - { - block_size = min(encrypted_start_2 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); - encrypted = 0; - } - else if (request.sector_offset >= encrypted_start_2 && request.sector_offset <= encrypted_end_2) - { - block_size = min(encrypted_end_2 + 1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE); - encrypted = 1; - } - block_size = min(end_lsn - request.sector_offset, block_size); - - response.result = sacd_read_block_raw(sacd_reader, request.sector_offset, block_size, response.data.bytes); - response.has_data = response.result > 0; - response.data.size = response.result * SACD_LSN_SIZE; - - // the ATAPI call which returns the flag if the disc is encrypted or not is unknown at this point. - // user reports tell me that the only non-encrypted discs out there are DSD 3 14/16 discs. - // this is a quick hack/fix for these discs. - if (encrypted && checked_for_non_encrypted_disc == 0) - { - switch (handle->area[0].area_toc->frame_format) - { - case FRAME_FORMAT_DSD_3_IN_14: - case FRAME_FORMAT_DSD_3_IN_16: - non_encrypted_disc = *(uint64_t *)(response.data.bytes + 16) == 0; - break; - } - - checked_for_non_encrypted_disc = 1; - } - - // encrypted blocks need to be decrypted first - if (encrypted && non_encrypted_disc == 0) - { - sacd_decrypt(sacd_reader, response.data.bytes, block_size); - } - } - } - break; - case ServerRequest_Type_DISC_OPEN: - response.type = ServerResponse_Type_DISC_OPENED; - sacd_reader = sacd_open("/dev_bdvd"); - if (sacd_reader) - { - handle = scarletbook_open(sacd_reader, 0); - checked_for_non_encrypted_disc = 0; - non_encrypted_disc = 0; - - if (handle) - { - // set the encryption range - if (handle->area[0].area_toc != 0) - { - encrypted_start_1 = handle->area[0].area_toc->track_start; - encrypted_end_1 = handle->area[0].area_toc->track_end; - } - if (handle->area[1].area_toc != 0) - { - encrypted_start_2 = handle->area[1].area_toc->track_start; - encrypted_end_2 = handle->area[1].area_toc->track_end; - } - - response.result = sacd_authenticate(sacd_reader); - } - } - break; - case ServerRequest_Type_DISC_CLOSE: - { - response.type = ServerResponse_Type_DISC_CLOSED; - if (handle) - { - scarletbook_close(handle); - handle = 0; - } - if (sacd_reader) - { - sacd_close(sacd_reader); - sacd_reader = 0; - } - response.result = 0; - } - break; - case ServerRequest_Type_DISC_SIZE: - response.type = ServerResponse_Type_DISC_SIZE; - if (sacd_reader) - { - response.result = sacd_get_total_sectors(sacd_reader); - } - break; - } - - // reset output stream - output = pb_ostream_from_buffer(output_buf, MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024); - - if (!pb_encode(&output, ServerResponse_fields, &response)) - { - break; - } - - /* We signal the end of a request with a 0 tag. */ - pb_write(&output, &zero, 1); - - // write the output buffer to the opened socket - { - bool ret; - size_t written; - ret = (socket_send(client, (char *) output_buf, output.bytes_written, &written, 0, 0) == IO_DONE && written == output.bytes_written); - - if (!ret) - break; - } - - if (request.type == ServerRequest_Type_DISC_CLOSE) - { - break; - } - } - - if (handle) - scarletbook_close(handle); - - if (sacd_reader) - sacd_close(sacd_reader); - - free(response.data.bytes); - free(output_buf); - - closesocket((int) *client); - client_connected = 0; - - sysThreadExit(0); -} - -void listener_thread(void *unused) -{ - sys_ppu_thread_t id; - struct sockaddr_in sa; - memset(&sa, 0, sizeof(sa)); - - sa.sin_family = AF_INET; - sa.sin_port = htons(2002); - sa.sin_addr.s_addr = htonl(INADDR_ANY); - - int list_s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - - // only 1 socket connection is allowed at once - if(bind(list_s, (struct sockaddr *)&sa, sizeof(sa)) == -1 || listen(list_s, 1) == -1) - { - sysThreadExit(0); - } - - int conn_s; - - while (!user_requested_exit()) - { - if((conn_s = accept(list_s, NULL, NULL)) > 0) - { - sysThreadCreate(&id, client_thread, (void *)&conn_s, 1337, 0x2000, 0, "client"); - sysThreadYield(); - } - } - - closesocket(list_s); - - sysThreadExit(0); -} diff --git a/tools/sacd_daemon/src/server.h b/tools/sacd_daemon/src/server.h deleted file mode 100644 index e0091da2..00000000 --- a/tools/sacd_daemon/src/server.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * SACD Ripper - http://code.google.com/p/sacd-ripper/ - * - * Copyright (c) 2010-2011 by respective authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __SERVER_H__ -#define __SERVER_H__ - -void listener_thread(void *unused); -int is_client_connected(void); - -#endif /* __SERVER_H__ */