/**************************************************************************************/ /* Cycfcntl.c, Libcyc source file */ /* File server and other functions */ /* Copyright(C)1999 Peter Armstrong */ /* Release 2.0 */ /**************************************************************************************/ /* includes */ #include #include "sys\ioctl.h" #include "sys\file.h" #include "stdio.h" #include "stdlib.h" #include "stdarg.h" #include "strings.h" #include "pad.h" #include "misc.h" #include "sendrec.h" #include "cycfcntl.h" #include "packets.h" /* externals */ extern struct link_info link; extern volatile struct cmds *cmd; extern int port_fd; extern volatile u_int vs_timer; extern u_int time[]; extern int vs_cmd; /* globals */ char *buffer_p; /* ptr to application data buffer */ u_short *rle_buffer; /* ptr to malloc'ed RLE data buffer */ int retries; /**************************************************************************************/ /* Test for connection to PC or psx */ /* Arguments: */ /* none */ /* Return value: */ /* 1 - connected to PC */ /* 0 - connected to another playstation */ /* -1 - no response */ /**************************************************************************************/ int cyc_ping(void) { u_char ping[CMD_SIZE] = {PC_CMD,'P','I','N','G',0,0,0x00}; link.ping = Send_PsxCmd(ping); return link.ping; } /**************************************************************************************/ /* Inform PC/other psx this playstation is about to exit */ /* Arguments: */ /* none */ /* Return value: */ /* 1 - exit command received by PC/psx */ /* 0 - command could not be sent, not connected to psx or PC */ /* -1 - comms error, timeout */ /**************************************************************************************/ int cyc_exit(void) { u_char exit_cmd[CMD_SIZE] = {PSX_CMD,'E','X','I','T',0,0,0x00}; int rtn = 0; /* send only if connected */ if((link.connected) || (link.ping == PNG_PC)) { rtn = Send_PsxCmd(exit_cmd); } return rtn; } /**************************************************************************************/ /* Display psx text and variables on the PC's monitor, as per standard printf */ /* Arguments: */ /* *format_str - printf format string */ /* ... - variable number of arguments passed to function */ /* Return value: */ /* number of characters printed */ /**************************************************************************************/ int cyc_printf(char *format_str,...) { va_list arg_ptr; u_char prtf_msg[CMD_SIZE] = {PSX2_CMD,'P','R','T','F',0,0,0x38}; /* chksum hard-coded */ char screen_string[200]; char *screen_p = screen_string; char print_str[8]; long len; long long_num; int print_num = 0,print_total = 0; char char_set[] = "cdiosuxXp"; /* create printf string before sending to PC */ va_start(arg_ptr,format_str); while(*format_str) { if(*format_str == '%') /* look for format spec start */ { len = (strcspn(format_str,char_set)+1); /* find specifier */ strncpy(print_str,format_str,len); print_str[len] = '\0'; format_str += len; long_num = va_arg(arg_ptr, long); print_num = sprintf(screen_p,print_str,long_num); screen_p += print_num; print_total += print_num; } else { *(screen_p++) = *(format_str++); print_total++; } } va_end(arg_ptr); *screen_p = '\0'; /* null terminate string */ len = (strlen(screen_string) + 1); /* if connected to PC, send command and string */ if(link.ping == PNG_PC) { vs_cmd = 0; /* send printf command to PC, to speed things up no PC reply is sent */ write(port_fd,prtf_msg,CMD_SIZE); write(port_fd,screen_string,len); /* send print string */ vs_cmd = 1; } else print_total = 0; return print_total; } /**************************************************************************************/ /* Start search for PC files */ /* Arguments: */ /* *fname - file name to search for */ /* attr - file attributes */ /* *ptr - pointer to structure storing file information */ /* Return value: */ /* >0 - file of specified type not found */ /* 0 - file found */ /* -2 - comms error */ /* *ptr structure contains the file information */ /**************************************************************************************/ int cyc_findfirst(char *fname,int attr, struct c_find *ptr) { u_char ffirst_cmd[CMD_SIZE] = {PC_CMD,'F','F','S','T',0,0,0x00}; int rtn = -2,find_val; if(Send_PsxCmd(ffirst_cmd) == OK) /* send findfirst command */ { vs_cmd = 0; /* disable command processing */ /* send file name and attributes to look for */ if((Send_Text(fname)) && (Send_Integer(attr))) { if(Read_Integer(&find_val)) /* read back return value */ { if(!find_val) /* zero if file found */ { /* read in file information */ if((Read_Integer(&ptr->attrib)) && (Read_Integer(&ptr->wr_time)) && (Read_Integer(&ptr->wr_date)) && (Read_Integer(&ptr->size)) && (Read_Text(ptr->name,NULL))) { rtn = 0; /* file found */ } } else /* file not found */ rtn = find_val; } } vs_cmd = 1; /* re-enable command processing */ } return rtn; } /**************************************************************************************/ /* Continue search for PC files */ /* Arguments: */ /* *ptr - pointer to structure storing file information */ /* Return value: */ /* >0 - no more files of the type specified */ /* 0 - file found, info stored in *ptr structure */ /* -2 - comms error */ /**************************************************************************************/ int cyc_findnext(struct c_find *ptr) { u_char fnext_cmd[CMD_SIZE] = {PC_CMD,'F','N','X','T',0,0,0x00}; int rtn = -2,find_val; if(Send_PsxCmd(fnext_cmd) == OK) /* send findnext command */ { vs_cmd = 0; if(Read_Integer(&find_val)) /* read return value */ { if(!find_val) /* zero equals success */ { /* read in file attributes, size and name */ if((Read_Integer(&ptr->attrib)) && (Read_Integer(&ptr->wr_time)) && (Read_Integer(&ptr->wr_date)) && (Read_Integer(&ptr->size)) && (Read_Text(ptr->name,NULL))) { rtn = 0; /* file found */ } } else rtn = find_val; /* file not found */ } vs_cmd = 1; } return rtn; } /**************************************************************************************/ /* Get PC file attributes */ /* Arguments: */ /* *fname - file of name */ /* *attrib - pointer to attributes store */ /* Return value: */ /* >0 - file not found */ /* 0 - file found and attributes returned */ /* -2 - comms error */ /**************************************************************************************/ int cyc_getfileattr(char *fname, u_int *attrib) { u_char getfattr_cmd[CMD_SIZE] = {PC_CMD,'G','F','A','T',0,0,0x00}; int rtn = -2,rtn_val; if(Send_PsxCmd(getfattr_cmd) == OK) { vs_cmd = 0; /* send file name */ if(Send_Text(fname)) { if(Read_Integer(&rtn_val)) /* read back return value */ { if(!rtn_val) /* zero equals success */ { if(Read_Integer(attrib)) { rtn = 0; /* attributes received */ } } else rtn = rtn_val; /* error, file not found */ } } vs_cmd = 1; } return rtn; } /**************************************************************************************/ /* Set PC file attributes */ /* Arguments: */ /* *fname - file of name */ /* attrib - attributes to set */ /* Return value: */ /* >0 - file error, attributes not set */ /* 0 - file found and attributes set */ /* -2 - comms error */ /**************************************************************************************/ int cyc_setfileattr(char *fname, u_int attrib) { u_char setfattr_cmd[CMD_SIZE] = {PC_CMD,'S','F','A','T',0,0,0x00}; int rtn = -2,rtn_val; if(Send_PsxCmd(setfattr_cmd) == OK) { vs_cmd = 0; /* send file name and attributes to set */ if((Send_Text(fname)) && (Send_Integer(attrib))) { if(Read_Integer(&rtn_val)) /* read back return value */ { if(!rtn_val) /* zero equals success */ { rtn = 0; /* attributes set */ } else rtn = rtn_val; /* error, file not found or access denied */ } } vs_cmd = 1; } return rtn; } /**************************************************************************************/ /* Open a PC file */ /* Arguments: */ /* *fname - ptr to path/name of file to open, 96 chars max */ /* mode - file opening mode, see cycfcntl.h */ /* Return value: */ /* >=0 - file descriptor attributed to file if successful */ /* -1 - unable to open file */ /* -2 - comms error */ /**************************************************************************************/ int cyc_open(char *fname,int mode) { u_char open_cmd[CMD_SIZE] = {PC_CMD,'O','P','E','N',0,0,0x00}; int fd = -2; if(Send_PsxCmd(open_cmd) == OK) /* inform PC psx wishes to open a file */ { vs_cmd = 0; if(Send_Text(fname)) /* the file's name */ { if(Send_Integer(mode)) /* the opening mode */ { /* read back the result of PC's attempt to open file */ Read_Integer(&fd); } } vs_cmd = 1; } return fd; } /**************************************************************************************/ /* Create a new PC file */ /* Arguments: */ /* *fname - ptr to path/name of file to open, 96 chars max */ /* pmode - file opening permission mode, see cycfcntl.h */ /* Return value: */ /* >=0 - file descriptor attributed to file if successful */ /* -1 - unable to open file */ /* -2 - comms error */ /**************************************************************************************/ int cyc_creat(char *fname,int pmode) { u_char creat_cmd[CMD_SIZE] = {PC_CMD,'C','R','E','A',0,0,0x00}; int fd = -2; if(Send_PsxCmd(creat_cmd) == OK) /* inform PC psx wishes to open a file */ { vs_cmd = 0; if(Send_Text(fname)) /* the file's name */ { if(Send_Integer(pmode)) /* the opening mode */ { /* read back the result of PC's attempt to create file */ Read_Integer(&fd); } } vs_cmd = 1; } return fd; } /**************************************************************************************/ /* Close a PC file */ /* Arguments: */ /* fd - file descriptor of open PC file */ /* Return value: */ /* 0 - file successfully closed */ /* -1 - an error has occurred */ /* -2 - comms error */ /**************************************************************************************/ int cyc_close(int fd) { u_char close_cmd[CMD_SIZE] = {PC_CMD,'C','L','O','S',0,0,0x00}; int rtn = -2; if(Send_PsxCmd(close_cmd) == OK) /* send close command */ { vs_cmd = 0; if(Send_Integer(fd)) /* send file's fd */ { Read_Integer(&rtn); /* read close() return value */ } vs_cmd = 1; } return rtn; } /**************************************************************************************/ /* Change the in-file position indicator */ /* Arguments: */ /* fd - file descriptor */ /* offset - number of bytes from origin */ /* origin - origin of above offset, see cycfcntl.h */ /* Return value: */ /* >=0 - new location of file position indicator */ /* -1 - an error has occurred */ /* -2 - comms error */ /**************************************************************************************/ long cyc_lseek(int fd,int offset,int origin) { u_char lseek_cmd[CMD_SIZE] = {PC_CMD,'L','S','E','K',0,0,0x00}; int pos = -2; if(Send_PsxCmd(lseek_cmd) == OK) /* send lseek command */ { vs_cmd = 0; if(Send_Integer(fd)) /* send file's fd */ { if(Send_Integer(offset)) /* offset from origin */ { if(Send_Integer(origin)) /* origin of offset */ { Read_Integer(&pos); /* read back lseek()'s return value */ } } } vs_cmd = 1; } return (long)pos; } /**************************************************************************************/ /* Delete a PC file */ /* Arguments: */ /* *fname - ptr to path/name of file to be deleted, 96 chars max */ /* Return value: */ /* 0 - file deleted */ /* -1 - an error has occurred */ /* -2 - comms error */ /**************************************************************************************/ int cyc_unlink(char *fname) { u_char unlink_cmd[CMD_SIZE] = {PC_CMD,'U','N','L','K',0,0,0x00}; int rtn = -2; if(Send_PsxCmd(unlink_cmd) == OK) /* send command to PC */ { vs_cmd = 0; if(Send_Text(fname)) /* file name */ { Read_Integer(&rtn); /* read unlink()'s return value */ } vs_cmd = 1; } return rtn; } /**************************************************************************************/ /* Pass a command to the PC's commmand processor; execute a DOS command */ /* Arguments: */ /* *cmd - ptr to command string, 96 chars max */ /* Return value: */ /* 0 - command successfully executed */ /* -1 - an error occurred, or command processor not present */ /* -2 - comms error */ /**************************************************************************************/ int cyc_system(char *cmd) { u_char system_cmd[CMD_SIZE] = {PC_CMD,'S','Y','S','T',0,0,0x00}; int rtn = -2; if(Send_PsxCmd(system_cmd) == OK) { vs_cmd = 0; if(Send_Text(cmd)) /* send DOS command */ { Read_Integer(&rtn); /* system()'s return value */ } vs_cmd = 1; } return rtn; } /**************************************************************************************/ /* Return the value of the in-file position indicator */ /* Arguments: */ /* fd - file descriptor */ /* Return value: */ /* >=0 - number of bytes the position indicator is away from the start of the file */ /* -1 - an error has occurred */ /* -2 - comms error */ /**************************************************************************************/ long cyc_tell(int fd) { u_char tell_cmd[CMD_SIZE] = {PC_CMD,'T','E','L','L',0,0,0x00}; int pos = -2; if(Send_PsxCmd(tell_cmd) == OK) /* send tell command */ { vs_cmd = 0; if(Send_Integer(fd)) { Read_Integer(&pos); /* read back in-file position */ } vs_cmd = 1; } return pos; } /**************************************************************************************/ /* Check for end of file */ /* Arguments: */ /* fd - file descriptor of file to check */ /* Return value: */ /* 1 - end of file reached */ /* 0 - not at end of file */ /* -1 - an error has occurred */ /* -2 - comms error */ /**************************************************************************************/ int cyc_eof(int fd) { u_char eof_cmd[CMD_SIZE] = {PC_CMD,'E','D','O','F',0,0,0x00}; int rtn = -2; if(Send_PsxCmd(eof_cmd) == OK) /* send eof command */ { vs_cmd = 0; if(Send_Integer(fd)) { Read_Integer(&rtn); /* read eof()'s return value */ } vs_cmd = 1; } return rtn; } /**************************************************************************************/ /* Read in data from a PC file */ /* Arguments: */ /* fd - file descriptor of file we wish to read from */ /* *buf - ptr to buffer to store read data */ /* num - number of bytes to read */ /* Return value: */ /* >0 - number of bytes read and stored from file */ /* 0 - end of file */ /* -1 - read error */ /* -2 - comms error */ /* -3 - malloc() failure */ /**************************************************************************************/ int cyc_read(int fd,char *buf,u_int num) { u_char read_cmd[CMD_SIZE] = {PC_CMD,'R','E','A','D',0,0,0x00}; char *store_p; char *chk_p; int rle,rec_num,read_num = 0; int i; int rtn = TIMEOUT; int read_rtn = 0; u_char checksum; u_char getsum; buffer_p = buf; /* init pointer to storage */ /* allocate RLE data buffer */ if(!(rle_buffer = (u_short *) malloc(RLE_BUF_SIZE))) return -3; if(Send_PsxCmd(read_cmd) == OK) /* send read command */ { vs_cmd = 0; /* send file descriptor, buffer address and number of bytes to read */ if((Send_Integer(fd)) && (Send_Integer((int)buf)) && (Send_Integer(num))) { while(num) { if(!Read_Integer(&read_rtn)) /* PC read()'s return value, number of bytes incoming */ break; if(read_rtn <= 0) /* PC read() error, eof, or out of retries */ { rtn = read_rtn; break; } /* check for normal or RLE encoded data */ if(read_rtn & RLE_BLK) { read_rtn &= 0x00007FFF; store_p = (char *)rle_buffer; /* store RLE data in separate buffer */ rle = 1; } else { store_p = buf; rle = 0; } retries = MAX_RETRIES; while(retries--) { ioctl(port_fd,FIOCNBLOCK,0); /* block reads */ EnterCriticalSection(); rec_num = read(port_fd,store_p,read_rtn); read(port_fd,(char *)&checksum,1); /* read checksum separately */ ExitCriticalSection(); ioctl(port_fd,FIOCNBLOCK,1); chk_p = (u_char *)store_p; /* calc checksum */ getsum = 0; for(i = 0;i < rec_num; i++) { getsum += *(chk_p++); } if(getsum == checksum) /* compare checksums */ { if(rle) { rec_num = RLEtoRaw(rec_num); /* decode data */ } else buffer_p = chk_p; /* bump up ptr to storage area for next lot of incoming data */ buf = buffer_p; read_num += rec_num; /* number of bytes read in total */ num -= rec_num; /* reduce total remaining */ Send_Reply(OK); /* inform PC data block good */ break; } else { Send_Reply(BAD); /* bad block */ } } } if(!num) /* all data read */ rtn = read_num; } } if(rtn >= 0) rtn = read_num; free(rle_buffer); vs_cmd = 1; return rtn; } /*------------------------------------------------------------------------------------*/ /* Convert a block of 16bit Run Length Encoded data back to ordinary data */ /* Arguments: */ /* data_size - size of encoded block in bytes */ /* Return value: */ /* size of decoded block in bytes */ /*------------------------------------------------------------------------------------*/ int RLEtoRaw(int data_size) { u_short *rle_p = rle_buffer; u_short *short_p = (u_short *)buffer_p; char *ch_p; u_int num,seq_val,raw_num = 0; /* work through block till end marker */ while(!(*rle_p & RLE_END)) { if(*rle_p & RLE_HDR) /* RLE data block */ { num = (*(rle_p++) & 0x7FFF); /* number of 16bit words with the same value */ raw_num += (num<<1); /* keep track of total in bytes */ seq_val = *(rle_p++); while(num--) { *(short_p++) = seq_val; } } else { /* run of normal data words */ num = (*(rle_p++) & 0x7FFF); /* number of normal words */ raw_num += (num<<1); while(num--) { *(short_p++) = *(rle_p++); } } } buffer_p = (char *)short_p; /* RLE block end, check for odd data byte in marker */ if(*rle_p &= 0x00FF) { *(buffer_p++) = (char) *rle_p; raw_num++; } return raw_num; } /**************************************************************************************/ /* Write data to a PC file */ /* Arguments: */ /* fd - file descriptor of file we wish to write to */ /* *buf - ptr to data */ /* num - number of bytes to write */ /* Return value: */ /* >=0 - number of bytes written, an error occurred if less than num */ /* -1 - write error */ /* -2 - comms error */ /**************************************************************************************/ int cyc_write(int fd,char *buf,u_int num) { u_char write_cmd[CMD_SIZE] = {PC_CMD,'W','R','T','E',0,0,0x00}; int i,w_size,w_num,w_count = 0; int rpy,rtn = TIMEOUT; u_char *buffer_p; u_char checksum; if(Send_PsxCmd(write_cmd) == OK) /* send write command */ { vs_cmd = 0; /* send file descriptor, buffer address and number of bytes to write */ if((Send_Integer(fd)) && (Send_Integer((int)buf)) && (Send_Integer(num))) /* number of bytes to write to PC */ { while(num) { w_size = num; if(w_size > BLK_SIZE) w_size = BLK_SIZE; /* write out up to 4k blocks at a time */ buffer_p = (u_char *)buf; checksum = 0; for(i = 0; i < w_size; i++) /* checksum data */ { checksum += *(buffer_p++); } retries = MAX_RETRIES; while(retries--) /* send out data to PC */ { write(port_fd,buf,w_size); /* send data */ write(port_fd,(char *)&checksum,1); /* send checksum */ if((rpy = Read_Reply(time[SIX_SEC])) != BAD) break; } /* test if out of retries, correct reply back, and read PC write() value from PC */ if((!retries) || (rpy != OK) || (!Read_Integer(&w_num))) break; if(w_num == w_size) /* write successful */ { buf = (char *)buffer_p; /* bump up ptr to next data block */ w_count += w_num; /* keep track of number of bytes successfully stored */ num -= w_num; /* deduct written number from total */ } else /* error, return -1 or number of bytes written */ { rtn = w_count; if((w_num == -1) && (!rtn)) rtn = -1; else { if(w_num != -1) rtn += w_num; } break; } } if(!num) rtn = w_count; } } vs_cmd = 1; return rtn; } /**************************************************************************************/ /* Read a data block from a second playstation */ /* Arguments: */ /* id - data block identifier, application specific */ /* **buf - a ptr either to a ptr containing the read buffer address, or a ptr used */ /* to store the malloc() return value */ /* size - size of read block, if zero ignore size, -1,malloc buffer to store block*/ /* Return value: */ /* >0 - number of bytes read and stored */ /* 0 (B_CNT_ERROR) - not connected to second playstation (via link cable) */ /* -1 (B_TIMEOUT) - comm error, no response */ /* -2 (B_CMD_MISMATCH) - read cmd not matched by write */ /* -3 (B_ID_MISMATCH) - block identifiers not the same */ /* -4 (B_SIZE_MISMATCH) - size of block not the same as 'size' */ /* -5 (B_MEM_FAIL) - unable to allocate block space */ /**************************************************************************************/ int block_read(int id, char **buf, int size) { int rtn = B_CNT_ERROR; if(link.connected) { if((rtn = Send_RdBlockCmd(id)) == OK) /* send/read and check commands */ { vs_cmd = 0; rtn = ReadIn_Block(buf,size); /* read in data block */ vs_cmd = 1; } } return rtn; } /*------------------------------------------------------------------------------------*/ /* Send block read command, read block write command from other psx */ /* Arguments: */ /* id - block identifier, sent within command */ /* Return value: */ /* 1 - cmds sent and received okay */ /* 0 - not connected to psx */ /* -1 - comms timeout */ /* -2 - command mismatch */ /* -3 - id mismatch */ /*------------------------------------------------------------------------------------*/ int Send_RdBlockCmd(int id) { u_char rdblk_cmd[CMD_SIZE] = {PSX_CMD,'B','R',0,0,0,0,0x00}; u_char xblk_cmd[CMD_SIZE] = {PSX_CMD,'B','X',0,0,0,0,0x00}; u_char *id_p = (u_char *)&id; u_int start_time; int i,rtn; /* copy id into command */ for(i = 3; i < 7; i++) { rdblk_cmd[i] = *(id_p++); } if((rtn = Send_PsxCmd(rdblk_cmd)) == OK) { rtn = B_TIMEOUT; start_time = vs_timer; while((!cmd->block) && ((vs_timer - start_time) < time[THREE_SEC])); if(cmd->block) { rtn--; if(cmd->block == B_WRITE) /* remote wishes to send block */ { rtn--; if(cmd->blk_id == id) /* correct block? */ { rtn = OK; } } } else Send_PsxCmd(xblk_cmd); /* if no block command from other psx cancel our block cmd */ } cmd->block = 0; return rtn; } /*------------------------------------------------------------------------------------*/ /* Prepare to read block from other psx */ /* Arguments: */ /* **buf - ptr to ptr to block store, or malloc'ed storage */ /* size - either expected block size, zero (ignore size), or -1 (malloc space) */ /* Return value: */ /* >0 - number of bytes read */ /* -1 - comms timeout */ /* -4 - block size mismatch */ /* -5 - malloc failure */ /*------------------------------------------------------------------------------------*/ int ReadIn_Block(char **buf,int size) { int rtn = B_TIMEOUT; int size_rpy = OK; int block_size; if(Read_Integer(&block_size)) /* size of block being sent */ { switch(size) { case -1: /* allocate space for incoming data */ if(!(*buf = (char *) malloc(block_size))) size_rpy = B_MEM_FAIL; case 0: /* block size known by application, ignore */ break; default: /* only accept block if same size as expected */ if(block_size != size) { size_rpy = B_SIZE_MISMATCH; } } if(Send_Integer(size_rpy)) { rtn = size_rpy; if(size_rpy == OK) { rtn = Read_Block(*buf,block_size); } } } return rtn; } /*------------------------------------------------------------------------------------*/ /* Read data block from other psx */ /* Arguments: */ /* *buf - pointer to block storage space */ /* size - number of bytes to read */ /* Return value: */ /* >0 - size of block read in */ /* -1 - error, comms timeout or out of retries */ /*------------------------------------------------------------------------------------*/ int Read_Block(char *buf, int size) { int i,rec_num,r_size,r_total = 0; int rtn = B_TIMEOUT; u_char *buffer_p; u_char checksum,getsum; while(size) { r_size = size; if(r_size > BLK_SIZE) /* in 4k blocks max */ r_size = BLK_SIZE; retries = MAX_RETRIES; while(retries--) { ioctl(port_fd,FIOCNBLOCK,0); /* block reads */ EnterCriticalSection(); rec_num = read(port_fd,buf,r_size); read(port_fd,(char *)&checksum,1); /* read checksum separately */ ExitCriticalSection(); ioctl(port_fd,FIOCNBLOCK,1); buffer_p = (u_char *)buf; /* calc checksum */ getsum = 0; for(i = 0;i < rec_num; i++) { getsum += *(buffer_p++); } if(getsum == checksum) /* compare checksums */ { /* bump up ptr to storage area for next lot of incoming data */ buf = (char *)buffer_p; size -= rec_num; /* reduce total remaining by number read */ r_total += rec_num; Send_Reply(OK); break; } else { Send_Reply(BAD); } if(!retries) break; } } if(!size) rtn = r_total; return rtn; } /**************************************************************************************/ /* Write a data block to a second playstation */ /* Arguments: */ /* id - data block identifier, application specific */ /* *buf - start address of block to send */ /* size - size of block, number of bytes to send */ /* Return value: */ /* >0 - number of bytes written */ /* 0 (B_CNT_ERROR) - not connected to second playstation (via link cable) */ /* -1 (B_TIMEOUT) - comm error, no response */ /* -2 (B_CMD_MISMATCH) - write cmd not matched by read */ /* -3 (B_ID_MISMATCH) - block identifiers not the same */ /* -4 (B_SIZE_MISMATCH) - block size mismatch on other psx */ /* -5 (B_MEM_FAIL) - malloc failure on other psx */ /**************************************************************************************/ int block_write(int id, char *buf, int size) { int rtn = B_CNT_ERROR; if(link.connected) { if((rtn = Send_WrBlockCmd(id)) == OK) /* send/read and verify block commands */ { vs_cmd = 0; rtn = WriteOut_Block(buf,size); vs_cmd = 1; } } return rtn; } /*------------------------------------------------------------------------------------*/ /* Send block write command, read in block read command from other psx */ /* Arguments: */ /* id - block identifier, sent within command */ /* Return value: */ /* 1 - cmds sent and received okay */ /* 0 - not connected to psx */ /* -1 - comms timeout */ /* -2 - command mismatch */ /* -3 - id mismatch */ /*------------------------------------------------------------------------------------*/ int Send_WrBlockCmd(int id) { u_char wrblk_cmd[CMD_SIZE] = {PSX_CMD,'B','W',0,0,0,0,0x00}; u_char xblk_cmd[CMD_SIZE] = {PSX_CMD,'B','X',0,0,0,0,0x00}; u_char *id_p = (u_char *)&id; u_int start_time; int i,rtn; /* put block identifier in command */ for(i = 3; i < 7; i++) { wrblk_cmd[i] = *(id_p++); } if((rtn = Send_PsxCmd(wrblk_cmd)) == OK) { rtn = B_TIMEOUT; start_time = vs_timer; /* wait for block command from other psx */ while((!cmd->block) && ((vs_timer - start_time) < time[THREE_SEC])); if(cmd->block) { rtn--; if(cmd->block == B_READ) /* remotes wants to read block */ { rtn--; if(cmd->blk_id == id) /* correct block? */ { rtn = OK; } } } else Send_PsxCmd(xblk_cmd); /* cancel command */ } cmd->block = 0; return rtn; } /*------------------------------------------------------------------------------------*/ /* Prepare to write block to other psx */ /* Arguments: */ /* *buf - ptr to block to send */ /* size - number of bytes to send */ /* Return value: */ /* >0 - number of bytes written */ /* -1 - comms timeout */ /* -4 - block size mismatch on other psx */ /* -5 - malloc failure on other psx */ /*------------------------------------------------------------------------------------*/ int WriteOut_Block(char *buf, int size) { int rtn = B_TIMEOUT; VSync(0); /* other psx not ready */ if(Send_Integer(size)) /* send block size to psx */ { if(Read_Integer(&rtn)) /* read back reply, if OK psx will accept block */ { if(rtn == OK) { rtn = Write_Block(buf,size); /* send block */ } } } return rtn; } /*------------------------------------------------------------------------------------*/ /* Write data block to other psx */ /* Arguments: */ /* *buf - pointer to block to send */ /* size - number of bytes to write */ /* Return value: */ /* >0 - size of block sent */ /* -1 - error, comms timeout */ /*------------------------------------------------------------------------------------*/ int Write_Block(char *buf, int size) { int i,w_size,w_total = 0; int rpy,rtn = B_TIMEOUT; u_char *buffer_p; u_char checksum; while(size) { w_size = size; if(w_size > BLK_SIZE) w_size = BLK_SIZE; /* 4k blocks max */ buffer_p = (u_char *)buf; checksum = 0; for(i = 0; i < w_size; i++) /* checksum data */ { checksum += *(buffer_p++); } retries = MAX_RETRIES; while(retries--) { write(port_fd,buf,w_size); /* send data */ write(port_fd,(char *)&checksum,1); /* send checksum */ if((rpy = Read_WrReply(time[THREE_SEC])) != BAD) break; } /* if out of retries or time-out exit */ if((!retries) || (rpy != OK)) break; buf = (char *)buffer_p; /* bump up ptr to next data block */ size -= w_size; /* deduct written number from total */ w_total += w_size; } if(!size) rtn = w_total; return rtn; }