DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/dos/dos_ioctl.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include <string.h>
00021 #include "dosbox.h"
00022 #include "callback.h"
00023 #include "mem.h"
00024 #include "regs.h"
00025 #include "dos_inc.h"
00026 
00027 bool DOS_IOCTL(void) {
00028         Bitu handle=0;Bit8u drive=0;
00029         /* calls 0-4,6,7,10,12,16 use a file handle */
00030         if ((reg_al<4) || (reg_al==0x06) || (reg_al==0x07) || (reg_al==0x0a) || (reg_al==0x0c) || (reg_al==0x10)) {
00031                 handle=RealHandle(reg_bx);
00032                 if (handle>=DOS_FILES) {
00033                         DOS_SetError(DOSERR_INVALID_HANDLE);
00034                         return false;
00035                 }
00036                 if (!Files[handle]) {
00037                         DOS_SetError(DOSERR_INVALID_HANDLE);
00038                         return false;
00039                 }
00040         } else if (reg_al<0x12) {                               /* those use a diskdrive except 0x0b */
00041                 if (reg_al!=0x0b) {
00042                         drive=reg_bl;if (!drive) drive = DOS_GetDefaultDrive();else drive--;
00043                         if( (drive >= 2) && !(( drive < DOS_DRIVES ) && Drives[drive]) ) {
00044                                 DOS_SetError(DOSERR_INVALID_DRIVE);
00045                                 return false;
00046                         }
00047                 }
00048         } else {
00049                 LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al);
00050                 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00051                 return false;
00052         }
00053         switch(reg_al) {
00054         case 0x00:              /* Get Device Information */
00055                 if (Files[handle]->GetInformation() & 0x8000) { //Check for device
00056                         reg_dx=Files[handle]->GetInformation();
00057                 } else {
00058                         Bit8u hdrive=Files[handle]->GetDrive();
00059                         if (hdrive==0xff) {
00060                                 LOG(LOG_IOCTL,LOG_NORMAL)("00:No drive set");
00061                                 hdrive=2;       // defaulting to C:
00062                         }
00063                         /* return drive number in lower 5 bits for block devices */
00064                         reg_dx=(Files[handle]->GetInformation()&0xffe0)|hdrive;
00065                 }
00066                 reg_ax=reg_dx; //Destroyed officially
00067                 return true;
00068         case 0x01:              /* Set Device Information */
00069                 if (reg_dh != 0) {
00070                         DOS_SetError(DOSERR_DATA_INVALID);
00071                         return false;
00072                 } else {
00073                         if (Files[handle]->GetInformation() & 0x8000) { //Check for device
00074                                 reg_al=(Bit8u)(Files[handle]->GetInformation() & 0xff);
00075                         } else {
00076                                 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00077                                 return false;
00078                         }
00079                 }
00080                 return true;
00081         case 0x02:              /* Read from Device Control Channel */
00082                 if (Files[handle]->GetInformation() & 0xc000) {
00083                         /* is character device with IOCTL support */
00084                         PhysPt bufptr=PhysMake(SegValue(ds),reg_dx);
00085                         Bit16u retcode=0;
00086                         if (((DOS_Device*)(Files[handle]))->ReadFromControlChannel(bufptr,reg_cx,&retcode)) {
00087                                 reg_ax=retcode;
00088                                 return true;
00089                         }
00090                 }
00091                 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00092                 return false;
00093         case 0x03:              /* Write to Device Control Channel */
00094                 if (Files[handle]->GetInformation() & 0xc000) {
00095                         /* is character device with IOCTL support */
00096                         PhysPt bufptr=PhysMake(SegValue(ds),reg_dx);
00097                         Bit16u retcode=0;
00098                         if (((DOS_Device*)(Files[handle]))->WriteToControlChannel(bufptr,reg_cx,&retcode)) {
00099                                 reg_ax=retcode;
00100                                 return true;
00101                         }
00102                 }
00103                 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00104                 return false;
00105         case 0x06:      /* Get Input Status */
00106                 if (Files[handle]->GetInformation() & 0x8000) {         //Check for device
00107                         reg_al=(Files[handle]->GetInformation() & 0x40) ? 0x0 : 0xff;
00108                 } else { // FILE
00109                         Bit32u oldlocation=0;
00110                         Files[handle]->Seek(&oldlocation, DOS_SEEK_CUR);
00111                         Bit32u endlocation=0;
00112                         Files[handle]->Seek(&endlocation, DOS_SEEK_END);
00113                         if(oldlocation < endlocation){//Still data available
00114                                 reg_al=0xff;
00115                         } else {
00116                                 reg_al=0x0; //EOF or beyond
00117                         }
00118                         Files[handle]->Seek(&oldlocation, DOS_SEEK_SET); //restore filelocation
00119                         LOG(LOG_IOCTL,LOG_NORMAL)("06:Used Get Input Status on regular file with handle %d",(int)handle);
00120                 }
00121                 return true;
00122         case 0x07:              /* Get Output Status */
00123                 LOG(LOG_IOCTL,LOG_NORMAL)("07:Fakes output status is ready for handle %d",(int)handle);
00124                 reg_al=0xff;
00125                 return true;
00126         case 0x08:              /* Check if block device removable */
00127                 /* cdrom drives and drive a&b are removable */
00128                 if (drive < 2) reg_ax=0;
00129                 else if (!Drives[drive]->isRemovable()) reg_ax=1;
00130                 else {
00131                         DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00132                         return false;
00133                 }
00134                 return true;
00135         case 0x09:              /* Check if block device remote */
00136                 if ((drive >= 2) && Drives[drive]->isRemote()) {
00137                         reg_dx=0x1000;  // device is remote
00138                         // undocumented bits always clear
00139                 } else {
00140                         reg_dx=0x0802;  // Open/Close supported; 32bit access supported (any use? fixes Fable installer)
00141                         // undocumented bits from device attribute word
00142                         // TODO Set bit 9 on drives that don't support direct I/O
00143                 }
00144                 reg_ax=0x300;
00145                 return true;
00146         case 0x0A:              /* Is Device of Handle Remote? */
00147                 reg_dx=0x8000;
00148                 LOG(LOG_IOCTL,LOG_NORMAL)("0A:Faked output: device of handle %d is remote",(int)handle);
00149                 return true;
00150         case 0x0B:              /* Set sharing retry count */
00151                 if (reg_dx==0) {
00152                         DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00153                         return false;
00154                 }
00155                 return true;
00156         case 0x0D:              /* Generic block device request */
00157                 {
00158                         if ((drive < 2) || Drives[drive]->isRemovable()) {
00159                                 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00160                                 return false;
00161                         }
00162                         PhysPt ptr      = SegPhys(ds)+reg_dx;
00163                         switch (reg_cl) {
00164                         case 0x60:              /* Get Device parameters */
00165                                 mem_writeb(ptr  ,0x03);                                 // special function
00166                                 mem_writeb(ptr+1,(drive>=2)?0x05:0x14); // fixed disc(5), 1.44 floppy(14)
00167                                 mem_writew(ptr+2,drive>=2);                             // nonremovable ?
00168                                 mem_writew(ptr+4,0x0000);                               // num of cylinders
00169                                 mem_writeb(ptr+6,0x00);                                 // media type (00=other type)
00170                                 // drive parameter block following
00171                                 mem_writeb(ptr+7,drive);                                // drive
00172                                 mem_writeb(ptr+8,0x00);                                 // unit number
00173                                 mem_writed(ptr+0x1f,0xffffffff);                // next parameter block
00174                                 break;
00175                         case 0x46:
00176                         case 0x66:      /* Volume label */
00177                                 {                       
00178                                         char const* bufin=Drives[drive]->GetLabel();
00179                                         char buffer[11] ={' '};
00180 
00181                                         char const* find_ext=strchr(bufin,'.');
00182                                         if (find_ext) {
00183                                                 Bitu size=(Bitu)(find_ext-bufin);
00184                                                 if (size>8) size=8;
00185                                                 memcpy(buffer,bufin,size);
00186                                                 find_ext++;
00187                                                 memcpy(buffer+size,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); 
00188                                         } else {
00189                                                 memcpy(buffer,bufin,(strlen(bufin) > 8) ? 8 : strlen(bufin));
00190                                         }
00191                         
00192                                         char buf2[8]={ 'F','A','T','1','6',' ',' ',' '};
00193                                         if(drive<2) buf2[4] = '2'; //FAT12 for floppies
00194 
00195                                         mem_writew(ptr+0,0);                    // 0
00196                                         mem_writed(ptr+2,0x1234);               //Serial number
00197                                         MEM_BlockWrite(ptr+6,buffer,11);//volumename
00198                                         if(reg_cl == 0x66) MEM_BlockWrite(ptr+0x11, buf2,8);//filesystem
00199                                 }
00200                                 break;
00201                         default :       
00202                                 LOG(LOG_IOCTL,LOG_ERROR)("DOS:IOCTL Call 0D:%2X Drive %2X unhandled",reg_cl,drive);
00203                                 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00204                                 return false;
00205                         }
00206                         return true;
00207                 }
00208         case 0x0E:                      /* Get Logical Drive Map */
00209                 if (drive < 2) {
00210                         if (Drives[drive]) reg_al=drive+1;
00211                         else reg_al=1;
00212                 } else if (Drives[drive]->isRemovable()) {
00213                         DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00214                         return false;
00215                 } else reg_al=0;        /* Only 1 logical drive assigned */
00216                 reg_ah=0x07;
00217                 return true;
00218         default:
00219                 LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al);
00220                 DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID);
00221                 break;
00222         }
00223         return false;
00224 }
00225 
00226 
00227 bool DOS_GetSTDINStatus(void) {
00228         Bit32u handle=RealHandle(STDIN);
00229         if (handle==0xFF) return false;
00230         if (Files[handle] && (Files[handle]->GetInformation() & 64)) return false;
00231         return true;
00232 }