home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************\
-
- disk driver interface module
-
- suntar 1.3, ⌐1991-92 Sauro & Gabriele Speranza
-
- This program is public domain, feel free to use it or part of it for anything
-
- \*******************************************************************************/
-
-
- #include "PB_sync.h"
- #include "antiglue.h"
-
- #include <DiskDvr.h>
- #include <DeviceMgr.h>
-
- #include "windows.h"
- #include "suntar.h"
-
- #define dp printf
-
- #define SINGLE_SIDED 2
- #define TWO_SIDED 3
- #define SUPERDRIVE 4
-
-
- extern short n_superdrives,last_drive,preferred_drive;
- extern short drive_type[max_drive];
- extern Boolean disco_espulso;
- extern sector_t file_current_s;
-
-
- OSErr get_format(DrvSts*,char*);
- Boolean is_msdos_disk(int);
- void verify_sectors(sector_t,char *,int);
-
- enum os_type riconosci_disco_mac(sector_2)
- unsigned char sector_2[512];
- {
- /* sector 2 contains the essential informations about the disk in both MFS and HFS */
- enum os_type i;
-
- if( *(int*) sector_2== 0xD2D7 )
- i=mac_MFS;
- else if( *(int*) sector_2== 0x4244)
- i=mac_HFS;
- else
- return unknown_os;
-
- if( sector_2[36]<=27 /*lunghezza del nome*/ &&
- *(int*)§or_2[12]>0 /* numero di files nel disco */)
- return i;
- else
- return unknown_os; /* two possible 16 bit values means 1 probability
- out of 32768 to recognize as Mac disk a non-Mac one,
- testing some other fields decreases it... */
- }
-
-
- static Boolean is_msdos_disk(drive_n)
- {
- /* ms-dos does not define a field containing some fixed value, but some
- fields are much larger than the small numbers they should hold, hence there is much
- redundancy, if all those fields have reasonable values, and at least some are not
- zero, then it must be an ms-dos disk
- Attention ! It uses the value of sectors_on_floppy which must be set to the correct
- value for the disk
- */
-
- struct bootsector { /* from mtools, msdos.h */
- /*0*/ unsigned char jump[3]; /* Jump to boot code */
- /*3*/ unsigned char banner[8]; /* OEM name & version */
- /*11*/ unsigned char secsiz[2]; /* Bytes per sector hopefully 512 */
- /*13*/ unsigned char clsiz; /* Cluster size in sectors */
- /*14*/ unsigned char nrsvsect[2]; /* Number of reserved (boot) sectors */
- /*16*/ unsigned char nfat; /* Number of FAT tables hopefully 2 */
- /*17*/ unsigned char dirents[2]; /* Number of directory slots */
- /*19*/ unsigned char psect[2]; /* Total sectors on disk */
- /*21*/ unsigned char descr; /* Media descriptor=first byte of FAT */
- /*22*/ unsigned char fatlen[2]; /* Sectors in FAT */
- /*24*/ unsigned char nsect[2]; /* Sectors/track */
- /*26*/ unsigned char nheads[2]; /* Heads */
- /*28*/ unsigned char nhs[2]; /* number of hidden sectors */
- /*30*/ unsigned char junk[482]; /* who cares? */
- };
-
-
- unsigned char buffer[512];
- int i;
- unsigned short n_s;
- Boolean maybe_old;
- static unsigned char offs[]= {11,12,13,15,16,18,23,25,26,27};
- static unsigned char limit[]={0, 2, 4, 0, 2, 2, 0, 0, 2, 0};
- static unsigned char min[]= {0, 2, 0, 0, 1, 0, 0, 0, 1, 0};
-
- read_one_sector(0,buffer,drive_n);
- if(err_code) return false;
-
- maybe_old=false;
- for(i=0;i<sizeof(offs);i++)
- if((unsigned char)buffer[offs[i]]>limit[i] ||
- (unsigned char)buffer[offs[i]]<min[i]){
- if(i<7) return false;
- maybe_old=true; /* those fields don't exist in disks formatted by a very
- old version of ms-dos */
- }
-
- lowbyte(n_s)= buffer[19];
- highbyte(n_s)= buffer[20];
-
- if(buffer[24]==0 || n_s != sectors_on_floppy || n_s%buffer[24]!=0 )
- maybe_old=true;
- /* bisogna accettare 9 e 18 ma anche 8 (160K) e 16 (320K) e 15 (1200K)
- e tanto vale anche un numero di settori qualunque purche' multiplo intero
- del numero di settori per traccia (a meno che l'hardware possa fornire i
- "veri" valori per questi parametri)
- -- I can't test the exact value of sectors per track since somebody
- could find a way to connect to the .Sony driver a disk which is not
- 720 nor 1440, but 360, 1200 or even the now obsolete 180, 160 and 320K
- formats
- */
- if(!maybe_old) return true;
- /* pero' in quei casi, la FAT sta comunque nel settore 1 e il primo byte della
- FAT (byte 0) vale FE o FC o FD o FF a seconda della densita' (160,180,320,360)
- -- in very old DOS some of the test variables were not defined, the remaining
- ones are too few to guarantee good probabilities of correctly guessing, but
- in those cases the FAT is in sector 1 and the first byte of FAT is
- FE or FC or FD or FF according to the density (160,180,320,360)
- */
- if(buffer[21]>=0xFC /* && buffer[21]<=0xFF */)
- return true;
- read_one_sector(1,buffer,drive_n);
- if(!err_code && buffer[0]>=0xFC)
- return true;
- return false;
- }
-
- /***********************************************************************/
-
-
- static Handle icon_handle;
- static Rect iconRect={10,16,42,48};
-
-
- pascal Boolean icon_update (DialogPtr,EventRecord *,short *);
- static pascal Boolean icon_update (theDialog, theEvent,itemHit)
- /* update routine for the disk initialization dialog: we've tried to
- copy the standard disk initialization dialog used by DIBadMount
- */
- DialogPtr theDialog;
- EventRecord *theEvent;
- short *itemHit;
- {
- if(theEvent->what==keyDown && ((unsigned char) theEvent->message==enter_key ||
- (unsigned char) theEvent->message==CR)){
- Rect frameRect;
- short kind;
- Handle h;
- *itemHit=1;
- GetDItem(theDialog,1,&kind,&h,&frameRect);
- SelectButton(h);
- return true;
- }
- else if(theEvent->what==updateEvt){
- if((WindowPtr)theEvent->message==theDialog){
- GrafPtr savePort;
- Rect frameRect;
- short kind;
- Handle h;
-
- GetPort( &savePort );
- SetPort(theDialog);
- PlotIcon(&iconRect,icon_handle);
- GetDItem(theDialog,1,&kind,&h,&frameRect);
- OutlineControl(h);
-
- SetPort(savePort);
- }
- else
- UpdateFilter(theEvent);
- }
- else if(theEvent->what==activateEvt)
- UpdateFilter(theEvent);
-
- return false;
- }
-
-
- void disk_format(make_dir) /* disk initialization routine */
- Boolean make_dir;
- {
- /* see Technical Notes 70 and 272 */
-
- extern Point badmount_point;
- cntrlParam ParamBlock;
- DialogTHndl dHandle;
- DialogPtr myDialog;
- int item,err;
-
-
- /* per dischi da 720K voglio usare un formato non ottenibile dalla DIBadMount,
- per gli altri voglio evitare la caratteristica del System 7 che accetta anche
- dischi con settori difettosi, quindi devo fare tutto da solo, compreso un dialogo
- possibilmente simile a quello standard
- -- 720K disks can't be obtained by DIBadMount. Other formats can, but System 7
- may return a noErr code for disks with bad sectors, marking them in the allocation
- table, hence it's better to avoid DIBadMount in any case. However, the user
- will feel better if my dialog looks like the standard disk initialization dialog
- */
-
- invalid_buffers();
- if( di.supports_720K){
- di.format_index=di.supports_720K; /* format_index contains the value for 800k, the
- maximum size, but I don't want that format */
- di.max_format=1440;
- }
-
- SetCursor(&arrow);
- /* procurati l'icona da mettere nel dialogo*/
- ParamBlock.ioRefNum=-5; /*.SONY driver*/
- ParamBlock.ioVRefNum=drive_number;
- ParamBlock.csCode=21; /* Return Physical Drive Icon */
- /*ParamBlock.ioCompletion=NULL; no, non serve se la chiamata Å sincrona */
- icon_handle=NewHandle(128); /* la routine ritorna un Ptr, ma PlotIcon vuole
- un handle e la Apple sconsiglia vivamente di crearsi un handle
- senza passare per NewHandle...
- -- I get a Ptr, but PlotIcon needs an handle and Apple discourages
- to create an handle without calling NewHandle, that could crash
- the machine, hence I must create a legal handle and copy the data
- */
- if( PBControlSync(&ParamBlock) != noErr)
- fillmem(*icon_handle,0,128);
- else
- mcopy(*icon_handle, *((Ptr*)&ParamBlock.csParam[0]), 128);
-
- /* crea e posiziona il dialogo */
- dHandle = (DialogTHndl)Get1Resource('DLOG',132);
- if (dHandle) {
- char buff[8];
- HLock((Handle)dHandle);
- PositionDialog( &((**dHandle).boundsRect));
- myDialog=GetNewDialog(132,NULL,-1L);
- if(in_Italia){
- short kind;
- Handle h;
- Rect r;
- GetDItem(myDialog,1,&kind,&h,&r);
- SetCTitle(h,di.is_not_initialized?"\pEspelli":"\pAnnulla");
- GetDItem(myDialog,2,&kind,&h,&r);
- SetCTitle(h,"\pInizializza");
- }
- else if(di.is_not_initialized){
- short kind;
- Handle h;
- Rect r;
- GetDItem(myDialog,1,&kind,&h,&r);
- SetCTitle(h,"\pEject");
- }
- my_itoa((long)(di.max_format>>1),&buff);
- c2pstr(buff);
- if(di.is_not_initialized)
- ParamText(in_Italia ? "\pDisco non inizializzato, verrê inizializzato a " :
- "\pUninitialized disk, it will be initialized at ",
- buff,"\p Kbytes",PNS);
- else
- ParamText(in_Italia ? "\pIl disco verrê inizializzato\ra " :
- "\pThis disk will be initialized\rat ", buff,"\p Kbytes",PNS);
-
- ModalDialog(icon_update,&item);
-
- if(item!=2){
- if(di.is_not_initialized) diskEject();
- }
- else{
- int *IPtr;
- GrafPtr savePort;
- static Rect rectScritta={0,54,40,300}; /* abbondare non nuoce */
- GetPort( &savePort );
- SetPort(myDialog);
- for(item=1;item<=3;item++){
- short kind;
- Handle h;
- Rect r;
- GetDItem(myDialog,item,&kind,&h,&r);
- InsetRect(&r,-4,-4);
- EraseRect(&r);
- }
- MoveTo(64,20);
- DrawString(in_Italia ? "\pInizializzazione..." :"\pInitializing...");
- PlotIcon(&iconRect,icon_handle); /* ci fosse un update non servito...*/
- SetCursor(&waitCursor);
-
- {CntrlParam parblk;
- char*pt=&parblk.csParam;
- parblk.ioRefNum=-5; /*.SONY driver*/
- parblk.ioVRefNum=drive_number;
- parblk.csCode=9; /* Track Cache Control */
- pt[0]=0; /* disable */
- pt[1]=-1; /* remove */
- PBControlSync(&parblk);
- }
-
- ParamBlock.ioRefNum=-5; /*.SONY driver*/
- ParamBlock.ioVRefNum=drive_number; /*1 for internal -- 2 for external drive*/
- ParamBlock.csCode=6; /*Format control code*/
- IPtr= (int*)&ParamBlock.csParam; /*point to it; pretend it's an int */
- *IPtr=di.format_index; /* see TN 272 */
-
- FlushVol(PNS,drive_number);
- di.disk_code=noMacDskErr;
- err=PBControlSync(&ParamBlock);
-
- {CntrlParam parblk;
- char*pt=&parblk.csParam;
- /* the initialization has changed the content of the disk,
- but the content of the track cache are NOT automatically
- invalidated, at least not always (it's not random, since when it
- happens it happens regularly, but I've not found any cause for
- that) hence I disable the track cache, do a write to be sure,
- and enable it again. I do not guarantee that it's OK now, since
- when it does not happen it does not happen regularly, and I
- can't do hundreds of formatting just to verify...*/
-
- fillmem(disk_buffer,0xF6,512);
- write_sectors(0,disk_buffer,1);
- parblk.ioRefNum=-5; /*.SONY driver*/
- parblk.ioVRefNum=drive_number;
- parblk.csCode=9; /* Track Cache Control */
- pt[0]=1; /* enable */
- pt[1]=1; /* install */
- PBControlSync(&parblk);
- }
-
- if(err==noErr){
-
- EraseRect(&rectScritta);
- MoveTo(64,20);
- DrawString(in_Italia ? "\pVerifica..." :"\pVerifying...");
- if(DIVerify(drive_number) == noErr){
- if(make_dir){
- EraseRect(&rectScritta);
- MoveTo(64,20);
- DrawString(in_Italia ? "\pCreazione catalogo..." :"\pCreating directory...");
- di.disk_code=DIZero (drive_number,di.max_format==1440 ? "\p720 Kbytes volume" :
- "\pUntitled");
- FlushVol (PNS,drive_number); /* contro le stranezze del system 7 che spesso lo
- richiede immediatamente dopo averlo espulso */
- UnmountVol(NULL,drive_number);
- }
- }
- else{
- beep_in_foreground();
- printf(in_Italia ? "Verifica fallita\n":"Verification failed\n");
- diskEject();
- }
- }
- else{
- beep_in_foreground();
- printf(in_Italia?"Inizializzazione fallita\n":"Initialization failed\n");
- diskEject();
- }
- SetPort(savePort);
- SetCursor(&arrow);
- }
- HUnlock ((Handle)dHandle);
- DisposDialog(myDialog);
- /*update_console();*/
- DisposHandle(icon_handle);
- }
- }
-
-
- /************** testa stato ************/
-
- short testa_stato(inPlace,verbose)
- /* calls the device driver to get informations about the current disk,
- then does some testing for useful data that the driver does not know;
- informations are returned in inPlace and the global variables di.is_write_protected,
- sectors_on_floppy , di.is_not_initialized, di.os (useful for any disk),
- di.max_format, di.format_index, di.supports_720K (useful only if the disk
- need be initialized)
- */
-
- short *inPlace;
- Boolean verbose;
- {
- int i;
- OSErr err;
- DrvSts status;
- char sector_buffer[512];
-
- i=5;
- do{ /* vedi get_format sul perchÄ faccio questo */
- err=DriveStatus(drive_number,&status);
- if(err) read_one_sector(0,sector_buffer,drive_number);
- }
- while(--i && err!=noErr);
- if(err){
- if(verbose){
- start_of_line();
- printf("Disk drive error %d\n",err);
- }
- return -1;
- }
- di.is_write_protected=status.writeProt;
- *inPlace=status.diskInPlace;
-
- err=get_format(&status,sector_buffer);
- if(err!=noErr){
- if(verbose) printf("Disk driver error\n");
- return -1;
- }
-
- /* discover if the disk is not initialized: there is not a device driver call
- for this purpose, but that range of errors is typical for non-initialized disks */
-
- read_one_sector(2,sector_buffer,drive_number);
- if( (di.is_not_initialized = err_code<=-66 && err_code>=-71) ){
- di.os=unknown_os;
- di.disk_code=ioErr;
-
- if(sectors_on_floppy==800){
- sectors_on_floppy=1600;
- if(verbose) printf(in_Italia?"Disco non inizializzato da 400/800/720 Kbytes\n":
- "400/800/720 Kbytes disk, not initialized\n");
- }
- else if(verbose)
- printf(in_Italia?"Disco non inizializzato da %ld Kbytes\n":
- "%ld Kbytes disk, not initialized\n",(long)sectors_on_floppy>>1);
-
- return 0;
- }
- if(err_code!=noErr) read_one_sector(2,sector_buffer,drive_number);
- if(err_code){
- printf("Disk read error %d\n",err_code);
- di.disk_code=err_code;
- di.os=unknown_os;
- return noErr;
- }
-
- di.os=riconosci_disco_mac(sector_buffer);
- if(di.os==unknown_os){
- di.disk_code=noMacDskErr;
- if(is_msdos_disk(drive_number) ){
- di.os=msdos;
- if(verbose){
- one_empty_line();
- printf(in_Italia?"Questo Å un disco MS-DOS da %ldK\n":
- "MS-DOS %ldK disk\n",(long)sectors_on_floppy>>1);
- }
- }
- else if(verbose){
- one_empty_line();
- printf(in_Italia?"Disco da %ldK\n":"%ldK disk\n", (long)sectors_on_floppy>>1);
- }
- }
- else{
- di.disk_code=noErr;
- if(verbose){
- one_empty_line();
- printf(in_Italia ? "Questo Å un disco Macintosh da %ldK\n" :
- "Macintosh %ldK disk\n", (long)sectors_on_floppy>>1);
- }
- }
-
- return noErr;
- }
-
- Boolean is_wrprot()
- /* sometimes the write protected information is not correct, being the state
- of the previously inserted disk rather than the current one. Asking the
- information a second time usually returns the correct value */
- {
- if(di.is_write_protected){ /* try again */
- DrvSts status;
- DriveStatus(drive_number,&status);
- di.is_write_protected=status.writeProt;
- }
- return di.is_write_protected;
- }
-
- static OSErr get_format(status,buffer)
- DrvSts*status;
- char*buffer; /* only to be used, it does not carry any information, but
- why allocate another buffer ? */
- {
- /* cerca il formato del disco attualmente nel drive; ritorna noErr se l'ha trovato,
- oppure il codice di errore ritornato dal device driver .Sony; poi, -1 se nessun
- formato Å quello del disco corrente (disco assente ?). Nella variabile
- sectors_on_floppy lascia il numero di settori, valido solo per noErr; comunque
- aggiorna supports_720K;
- -- uses the new status calls to get informations about the current disk: it
- may return the error code given by PBStatus, or noErr if succeeded, or -1
- if none of the supported disk formats is marked as being that of the current disk;
- supports_720K is adjusted in any case.
- */
- long tabella[12];
- CntrlParam parblk;
- int j;
- OSErr err;
-
- /* a volte succede che inserisco il disco quasi insieme all'emissione del
- comando da men¥, il disco viene espulso ma NON da parte della diskEject che libera
- il drive, ma da parte del chiamante che si vede ritornare -1 da testa_stato,
- perchÄ la PBStatus ritorna offLinErr. Unica soluzione, fare una read appena
- prima, e certo riprovare pi¥ volte aiuta
- */
- j=5;
- do{
- fillmem(&(parblk.qLink),0,sizeof(CntrlParam));
- parblk.ioRefNum=-5;
- parblk.ioVRefNum=drive_number;
- parblk.csCode=6;
- parblk.csParam[0]=6; /* dim tabella */
-
- *(long*)(&(parblk.csParam[1])) = (long)&(tabella[0]);
- err=PBStatusSync (&parblk.qLink);
-
- /*dp("err =%d(%d)\n",err,drive_number);*/
- if(err==offLinErr) read_one_sector(0,buffer,drive_number);
- }
- while(err==offLinErr&&--j);
- di.supports_720K=0;
-
- if(err==statusErr){ /* non c'Å una versione recente del device driver,
- ma allora non supporta i SuperDrive e i formati possibili sono questi:
- -- the device driver does not support the new status calls, but
- old drivers don't support SuperDrives and DriveStatus suffices to
- build the informations I need
- */
- sectors_on_floppy= (status->twoSideFmt==-1) ? 1600 : 800;
- if(status->sides&0x80){
- di.max_format=1600;
- di.format_index=2;
- }
- else{
- di.max_format=800;
- di.format_index=1;
- }
- return noErr;
- }
- else if(err != noErr)
- return err;
-
- sectors_on_floppy=0;
- /*di.format_index=0;*/
- di.max_format=-1;
- for(j=0;j<parblk.csParam[0];j++){
- if(tabella[j+j+1] & 0x40000000L) /* bit "current disk has this format" */
- sectors_on_floppy=tabella[j+j];
- if(tabella[j+j]==1440) di.supports_720K=j+1;
- if(tabella[j+j]>di.max_format){
- di.max_format=tabella[j+j];
- di.format_index=j+1;
- }
- }
- /*sectors_on_floppy=100; /*per le prove multivolume, mica voglio perdere tempo!
- -- for debugging multivolume formats, put few data
- on each disk, otherwise the tests will last hours ! */
- if(sectors_on_floppy==0) return -1;
- return noErr;
- }
-
-
- void identifica_hardware()
- /* get informations about the .Sony device driver and the disk drives */
- {
- /* i 4 LSB di parblk.csParam[1] valgono:
- -- from TN272: the four LSB of parblk.csParam[1] are coded as follows:
- 0 no such drive
- 1 unspecified drive
- 2 400K Sony
- 3 800K Sony
- 4 SuperDrive (400K/800K GCR, 720K/1440K MFM)
- 5 reserved
- 6 reserved
- 7 Hard Disk 20
- 8-15 reserved
-
- anyway, since in the News somebody tells that Apple is going to put out
- a new floppy disk drive (maybe 2.88M, maybe a floptical 20M), suntar
- accepts 5 as a SuperDrive-compatible disk: there is no reason why Apple
- should not use that code nor make that drive SuperDrive-incompatible
- */
- CntrlParam parblk;
- int i,n_drives=0;
- n_superdrives=0;
- last_drive=0;
- for (i=1;i<=max_drive;i++){ /* ci possono essere buchi, ma comunque mai oltre l'unitê 4 !
- -- a Macintosh can't go beyond unit 4, but there may be
- an hole since old systems assigned 3 to an external drive even
- if unit 2 was not present
- */
- drive_type[i-1]=0;
- parblk.ioRefNum=-5;
- parblk.ioVRefNum=i;
- parblk.csCode=23;
-
- err_code=PBControlSync (&(parblk.qLink));
- /*printf("%d %x %d\n",i,parblk.csParam[1],err_code);*/
- if(err_code==controlErr){ /* una versione del disk driver anteriore a quella
- che gestisce i SuperDrive
- -- an old version of the device driver: get
- informations from DriveStatus
- */
- DrvSts status;
- err_code=DriveStatus(drive_number,&status); /* per sapere se il drive esiste */
- if(err_code==noErr && status.installed>=0){
- if(n_superdrives==0) preferred_drive=i;
- last_drive=i;
- n_drives++;
- drive_type[i-1]= (status.sides&0x80) ? TWO_SIDED|0x8000 : SINGLE_SIDED|0x8000;
- }
- }
- else if(err_code==noErr){ /* OK, puÿ essere un SuperDrive */
- int j;
- drive_type[i-1]=parblk.csParam[1]&0x7FFF;
- j= parblk.csParam[1] &0xF;
- if(j==SUPERDRIVE || j==SUPERDRIVE+1){
- preferred_drive=i;
- n_superdrives++;
- }
- if(n_superdrives==0) preferred_drive=i;
- last_drive=i;
- n_drives++;
- }
- }
-
- if(n_superdrives>1 || n_superdrives==0&&n_drives>1)
- preferred_drive=0;
-
-
- #if 0 /* no more useful, since now I do my own buffering */
- if(preferred_drive){
- parblk.ioRefNum=-5; /*.SONY driver*/
- parblk.ioVRefNum=preferred_drive;
- parblk.csCode=9; /* Track Cache Control */
- *(short*)&parblk.csParam =1*256+1; /* Track cache on: pare che sia la normalitê,
- ma non si sa mai
- -- track cache on: suntar is much faster.
- Really, that's the default mode on our Mac,
- but we don't know about other Macs. Well, in
- theory one should restore the original situation
- when quitting, but there seems to be no easy
- way to know which was the current setting:
- "When the cache is removed, 680x0 register D0
- contains the previous size of the cache",
- (TN 272) but that does NOT work !, in D0
- it always return 0 for noError, looking at D0.L,
- D1.L and A0.L does not yield any number that
- could be that thing
- */
-
- PBControlSync(&parblk);
- }
- #endif
-
- if(n_superdrives==0 && !accetta_GCR){
- ParamText(in_Italia ?
- "\pNon hai un SuperDrive, quindi non potrai\rleggere dischi scritti su un sistema UNIX":
- "\pYou have no SuperDrive, you can\'t read\rdisks written on an UNIX machine",
- PNS,PNS,PNS );
- my_alert();
- }
-
- }
-
- /******************* buffering *********************************/
-
- /* suntar either writes or reads, and when it does neither of the two
- it's better to flush the buffers anyway, since the disk could be ejected
- without letting him know. Hence it's better to let the buffer empty even
- in cases when the data is still good. Otherwise, this is a simple
- implementation of a write-back cache, consisting of a single "cache line" with
- status information for each sector.
-
- Probably it would be faster using Async calls, but that's more difficult,
- and an old Apple Technical Note told that the first versions of MultiFinder
- did not let an application go to background while it had some Async calls
- pending.
- Really, in many cases the best thing would be to launch one independent Async
- call for each sector, so the operation will start as sooner as possible,
- with the highest degree of parallelism. But that's even more difficult and
- might cause more risks for incompatibility; and is the Mac hardware and software
- able to exploit that potential parallelism, or is everything serialized anyway ?.
- */
-
-
- short floppy_buffer_size;
-
- static char* buffers_base;
- static sector_t first_in_buffer;
- static enum{empty, full, dirty };
- static char *buffer_state;
- static Boolean traccia_difettosa;
-
- void invalid_buffers(void);
- void invalid_buffers()
- {
- short i;
- for(i=0;i<floppy_buffer_size;i++)
- buffer_state[i]=empty;
- first_in_buffer= -floppy_buffer_size;
- traccia_difettosa=false;
- }
-
- void invalid_after(start_sector)
- sector_t start_sector;
- {
- short i;
- for(i=0;i<floppy_buffer_size;i++)
- if(first_in_buffer+i >= start_sector) buffer_state[i]=empty;
- }
-
-
- void init_buffering()
- {
- ResrvMem ((Size)floppy_buffer_size);
- buffer_state=NewPtr((Size)floppy_buffer_size);
- invalid_buffers();
- buffers_base=NewPtr((Size)floppy_buffer_size*512);
- check_allocated(buffers_base);
- }
-
- void check_allocated(p)
- void *p;
- {
- if(!p){
- ParamText("\pCan\'t allocate disk buffers\rReduce their size or increase the partition",
- PNS,PNS,PNS);
- my_alert();
- ExitToShell();
- }
- }
-
- void flush_buffers()
- {
- short primo=0, ultimo;
-
- /*int i;for(i=0;i<floppy_buffer_size;i++)
- printf("%d ",buffer_state[i]);
- printf("\n"); */
-
- err_code=noErr;
- while(primo<floppy_buffer_size){
- while(buffer_state[primo]!=dirty && primo<floppy_buffer_size) primo++;
- if(primo>=floppy_buffer_size) break;
- ultimo=primo+1;
- while(ultimo<floppy_buffer_size && buffer_state[ultimo]==dirty ) ultimo++;
- /*dp("write %ld,%ld\n",(long)(first_in_buffer+primo),(long)(first_in_buffer+ultimo-1));*/
- write_sectors(first_in_buffer+primo,buffers_base+((sector_t)primo<<9),ultimo-primo);
- if(err_code){
- /*dp("errore, riprovo\n");*/
- write_sectors(first_in_buffer+primo,buffers_base+((sector_t)primo<<9),ultimo-primo);
- if(err_code){
- invalid_buffers();
- return;
- }
- }
- if(verify_writes){
- verify_sectors(first_in_buffer+primo,buffers_base+((sector_t)primo<<9),ultimo-primo);
- if(err_code){
- start_of_line();
- printf("Write/verify: verification failed (sector");
- if(primo==ultimo-1)
- printf(" %ld)\n",(long)(first_in_buffer+(long)primo));
- else
- printf("s %ld to %ld)\n",(long)(first_in_buffer+(long)primo),
- first_in_buffer+(long)ultimo-1);
- invalid_buffers();
- raise_error();
- }
- }
- primo=ultimo;
- }
- invalid_buffers();
- }
-
- Boolean dirty_buffers()
- {
- short i;
- for(i=0;i<floppy_buffer_size;i++)
- if(buffer_state[i]==dirty) return true;
- return false;
- }
-
- void leggi_settore(n_sect,buffer)
- sector_t n_sect;
- char *buffer;
- {
- char *pos_in_buffer;
-
- if(n_sect>=first_in_buffer && n_sect<first_in_buffer+floppy_buffer_size){ /* match */
- pos_in_buffer = buffers_base+((n_sect-first_in_buffer)<<9);
-
- if( buffer_state[n_sect-first_in_buffer]!=empty){
- /*dp("match lettura %ld\n",n_sect);*/
- mcopy(buffer,pos_in_buffer,512);
- err_code=noErr;
- return;
- }
- if(traccia_difettosa){ /* defective sector on the track... */
- read_sectors(n_sect, pos_in_buffer, 1);
- mcopy(buffer,pos_in_buffer,512);
- if(!err_code) buffer_state[n_sect-first_in_buffer]=full;
- return;
- }
- }
-
- flush_buffers();
- /* invalid_buffers(); */
-
- traccia_difettosa=false;
- first_in_buffer= n_sect - n_sect%floppy_buffer_size;
- pos_in_buffer= buffers_base+((n_sect-first_in_buffer)<<9);
-
- if(fase==reading_disk && ! listonly || n_sect<=2){ /* sectors 0 and 2 are read
- many times, it's better to read all of them even during a List */
- short n_to_read;
- /*dp("leggo multiplo %ld\n",n_sect);*/
- if(first_in_buffer+floppy_buffer_size<=sectors_on_floppy)
- n_to_read= floppy_buffer_size;
- else
- n_to_read=sectors_on_floppy-first_in_buffer;
- read_sectors(first_in_buffer,buffers_base,n_to_read);
- if(! err_code){
- short i;
- for(i=0;i<n_to_read;i++)
- buffer_state[i]=full;
- for(;i<floppy_buffer_size;i++)
- buffer_state[i]=empty;
- mcopy(buffer,pos_in_buffer,512);
- return;
- }
- traccia_difettosa=true;
- }
-
- /*dp("leggo singolo %ld\n",n_sect);*/
- read_sectors(n_sect, pos_in_buffer, 1);
- mcopy(buffer,pos_in_buffer,512);
- if(!err_code) buffer_state[n_sect-first_in_buffer]=full;return;
- }
-
- void scrivi_settore(n_sect,buffer)
- sector_t n_sect;
- char *buffer;
- {
- if(n_sect<first_in_buffer || n_sect>=first_in_buffer+floppy_buffer_size ){
- /*dp("chiedo flush %ld\n",n_sect);*/
- flush_buffers();
- if(err_code) return;
- /* invalid_buffers(); */
- first_in_buffer= n_sect - n_sect%floppy_buffer_size;
- }
- /*else dp("match write %ld\n",n_sect);*/
- mcopy(buffers_base+((n_sect-first_in_buffer)<<9),buffer,512);
- buffer_state[n_sect-first_in_buffer]=dirty;
- err_code=noErr;
- return;
- }
-
- /************** assembly language *******************************/
-
-
- /* from Inside Macintosh volume II page 216 */
-
-
- void diskEject() /* ho il sospetto si riesca a fare anche ad alto livello,
- dovrebbe essere permesso passare un drive number al posto
- di vRefNum
- -- probably it can be done in C */
- {
- ultimo_disco_espulso=true;
- disco_espulso=true;
- flush_buffers();
- if(drive_number==0) return;
- asm{
- moveq #31,D0 /* #<ioVQElSize/2>-1,D0 */
- clearloop:
- clr.w -(SP)
- dbra D0,@clearloop
- move.l SP,A0
- move.w #-5,0x18(A0) /* #-5,ioRefNum(A0) */
- move.w drive_number,0x16(A0) /* drive_number,ioDrvNum(A0) */
- move.w #7,0x1A(A0) /* #ejectCode,csCode(A0) */
- dc.w 0xA017 /* _Eject */
- add.w #0x40,SP /* #ioVQElSize,SP */
- }
- drive_number=0;
- }
-
- /**********************************/
- void read_sectors(sect_n,buffer,n_sectors)
- int n_sectors;
-
- sector_t sect_n;
- char *buffer;
- {
- long count;
-
- if(file_aperto){
- /* if working from a file rather than a disk... */
- err_code=0;
- if(sect_n!=file_current_s)
- err_code=SetFPos(inputFile,fsFromStart,(long)sect_n<<9);
- if(err_code==eofErr)
- err_code=sectNFErr; /* sector not found error */
- else if(!err_code){
- count=(long)n_sectors<<9;
- err_code=FSRead(inputFile,&count,buffer);
- if(!err_code && !count) err_code=eofErr;
- if(err_code==eofErr && count!=0){
- fillmem(&buffer[count],0,(n_sectors<<9)-(int)count);
- err_code=noErr;
- }
- }
- if(err_code)
- file_current_s=-1;
- else
- file_current_s=sect_n+n_sectors;
- return;
- }
-
- asm{
- moveq #24,D0 /* #<ioQElsize/2>-1,D0 */
- clrloop:
- clr.w -(SP)
- dbra D0,@clrloop
- move.l SP,A0
- move.w #-5,0x18(A0) /* #-5,ioRefNum(A0) */
- move.w drive_number,0x16(A0) /* drive_number,ioDrvNum(A0) */
- move.w #1,0x2C(A0) /* #1,ioPosMode(A0) absolute positioning */
- #if SECTOR_T_SIZE==4
- move.l sect_n,D0
- lsl.l #4,D0 /* 9 is too big... */
- lsl.l #5,D0
- #else
- move.w sect_n,D0
- mulu #512,D0 /* does both int->long conversion and shift */
- #endif
- move.l D0,0x2E(A0) /* D0,ioPosOffset(A0) */
-
- move.w n_sectors,D0
- mulu #512,D0
- move.l D0,0x24(A0) /* D0,ioReqCount(A0) /* read n_sectors sectors */
- move.l buffer,A1
- move.l A1,0x20(A0) /* A1,ioBuffer(A0) */
- dc.w 0xA002 /* _Read */
- move.w 0x10(A0),err_code /* ioResult(A0),err_code */
- /*move.l 0x28(A0),count*/ /* ioActCount(A0),count) */
- add.w #0x32,SP /* #ioQElSize,SP */
- }
- }
-
- void read_one_sector(sect_n,buffer,drive_n)
- /* it reads from the disk even when read_sectors is redirected to read from a file... */
- sector_t sect_n;
- char *buffer;
- short drive_n;
- {
- asm{
- moveq #24,D0 /* #<ioQElsize/2>-1,D0 */
- clrloop:
- clr.w -(SP)
- dbra D0,@clrloop
- move.l SP,A0
- move.w #-5,0x18(A0) /* #-5,ioRefNum(A0) */
- move.w drive_n,0x16(A0) /* drive_number,ioDrvNum(A0) */
- move.w #1,0x2C(A0) /* #1,ioPosMode(A0) absolute positioning */
- #if SECTOR_T_SIZE==4
- move.l sect_n,D0
- lsl.l #4,D0 /* 9 is too big... */
- lsl.l #5,D0
- #else
- move.w sect_n,D0
- mulu #512,D0 /* does both int->long conversion and shift */
- #endif
- move.l D0,0x2E(A0) /* D0,ioPosOffset(A0) */
-
- move.l #512,0x24(A0)
- move.l buffer,A1
- move.l A1,0x20(A0) /* A1,ioBuffer(A0) */
- dc.w 0xA002 /* _Read */
- move.w 0x10(A0),err_code /* ioResult(A0),err_code */
- add.w #0x32,SP /* #ioQElSize,SP */
-
- }
- }
-
-
- /******************************/
-
- void write_sectors(sect_n,buffer,n_sectors)
- sector_t sect_n;
- char *buffer;
- int n_sectors;
- {
- /*err_code=0;
- return;*/
-
- asm{
- moveq #24,D0 /* #<ioQElsize/2>-1,D0 */
- clrloop:
- clr.w -(SP)
- dbra D0,@clrloop
- move.l SP,A0
- move.w #-5,0x18(A0) /* #-5,ioRefNum(A0) */
- move.w drive_number,0x16(A0) /* drive_number,ioDrvNum(A0) */
- move.w #1,0x2C(A0) /* #1,ioPosMode(A0) absolute positioning */
- #if SECTOR_T_SIZE==4
- move.l sect_n,D0
- lsl.l #4,D0
- lsl.l #5,D0
- #else
- move.w sect_n,D0
- mulu #512,D0
- #endif
- move.l D0,0x2E(A0) /* D0,ioPosOffset(A0) */
-
- move.w n_sectors,D0
- mulu #512,D0
- move.l D0,0x24(A0) /* D0,ioReqCount(A0) /* write n_sectors sectors */
- move.l buffer,A1
- move.l A1,0x20(A0) /* A1,ioBuffer(A0) */
- dc.w 0xA003 /* _Write */
- move.w 0x10(A0),err_code /* ioResult(A0),err_code */
- add.w #0x32,SP /* #ioQElSize,SP */
- }
- }
-
-
- static void verify_sectors(sect_n,buffer,n_sectors)
- sector_t sect_n;
- char *buffer;
- int n_sectors;
- {
- asm{
- moveq #24,D0 /* #<ioQElsize/2>-1,D0 */
- clrloop:
- clr.w -(SP)
- dbra D0,@clrloop
- move.l SP,A0
- move.w #-5,0x18(A0) /* #-5,ioRefNum(A0) */
- move.w drive_number,0x16(A0) /* drive_number,ioDrvNum(A0) */
- move.w #65,0x2C(A0) /* #1+64,ioPosMode(A0) absolute positioning &
- read/verify */
- #if SECTOR_T_SIZE==4
- move.l sect_n,D0
- lsl.l #4,D0 /* 9 is too big... */
- lsl.l #5,D0
- #else
- move.w sect_n,D0
- mulu #512,D0 /* does both int->long conversion and shift */
- #endif
- move.l D0,0x2E(A0) /* D0,ioPosOffset(A0) */
-
- move.w n_sectors,D0
- mulu #512,D0
- move.l D0,0x24(A0) /* D0,ioReqCount(A0) /* read n_sectors sectors */
- move.l buffer,A1
- move.l A1,0x20(A0) /* A1,ioBuffer(A0) */
- dc.w 0xA002 /* _Read */
- move.w 0x10(A0),err_code /* ioResult(A0),err_code */
- add.w #0x32,SP /* #ioQElSize,SP */
-
- }
- }