📄 matcd.c
字号:
outb(port+CMD,*cp++); /*must be sent within 10msec or*/ } /*the drive will ignore the cmd*/ splx(level); /*------------------------------------------------*/ return;}/*--------------------------------------------------------------------------- draincmd - Makes certain the bus is idle and throws away any residual data from the drive if there is any. Called as preface to most commands. Added in Edit 5. This was added because switching drive modes causes the drive to emit buffers that were meant to be sent to the D-to-A to be sent to the host. See setmode.---------------------------------------------------------------------------*/void draincmd(int port,int cdrive,int ldrive){ int i,z; i=inb(port+STATUS); if ((i & (DTEN|STEN)) == (DTEN|STEN)) return; printf("matcd%d: in draincmd: bus not idle %x - trying to fix\n", ldrive,inb(port+STATUS)); if ((i & (DTEN|STEN)) == STEN) {#ifdef DEBUGCMD printf("matcd%d: Data present READING - ",ldrive);#endif /*DEBUGCMD*/ i=0; outb(port+PHASE,1); /*<16>Enable data read*/ while ((inb(port+STATUS) & (DTEN|STEN)) == STEN) { inb(port+DATA); /*<21>Ok for Creative*/ inb(port+ALTDATA); /*<21>Ok for others*/ i++; } outb(port+PHASE,0);#ifdef DEBUGCMD printf("%d bytes read\n",i);#endif /*DEBUGCMD*/ }#ifdef DEBUGCMD printf("matcd%d: Now read status: ",ldrive);#endif /*DEBUGCMD*/ i=get_stat(port,ldrive); /*Read status byte*/ z=inb(port+STATUS); /*Read bus status*/#ifdef DEBUGCMD printf("Data byte %x and status is now %x\n",i,z);#endif /*DEBUGCMD*/ if ((z & (DTEN|STEN)) != (DTEN|STEN)) { printf("matcd%d: Bus not idle %x - resetting\n", cdrive,inb(port+STATUS)); doreset(port,cdrive); } return;}/*--------------------------------------------------------------------------- selectdrive - Swaps drive select bits On Creative SB/SB16/stand-alone adapters, possibly to make them hard to reverse engineer, the drive select signals are swapped.---------------------------------------------------------------------------*/void selectdrive(int port,int drive){ switch(drive) { case 0: /*0x00 -> 0x00*/ outb(port+SELECT,CRDRIVE0); break; case 1: /*0x01 -> 0x02*/ outb(port+SELECT,CRDRIVE1); break; case 2: /*0x02 -> 0x01*/ outb(port+SELECT,CRDRIVE2); break; case 3: /*0x03 -> 0x03*/ outb(port+SELECT,CRDRIVE3); break; } return;}/*--------------------------------------------------------------------------- matcd_pread - Read small blocks of control data from a drive---------------------------------------------------------------------------*/void matcd_pread(int port, int count, unsigned char * data){ int i; for (i=0; i<count; i++) { *data++ = inb(port+CMD); } return;}/*--------------------------------------------------------------------------- matcd_setmode - Configures disc to run in the desired data mode This routine assumes the drive is already idle.NOTE - Undocumented action of hardware: If you change (or reaffirm) data modes with MODESELECT + BLOCKPARAM immediately after a command was issued that aborted a DA play operation, the drive will unexpectedly return 2532 bytes of data in a data phase on the first or second subsequent command. Original Symptom: drive will refuse to go idle after reading data and status expected for a command. State mechanics for this are not fully understood.---------------------------------------------------------------------------*/static intmatcd_setmode(int ldrive, int mode){ struct matcd_data *cd; int retries; int i,port,cdrive; unsigned char cmd[MAXCMDSIZ]; cd = matcd_data + ldrive; retries=3; cdrive=ldrive&0x03; port=cd->iobase; if (cd->drivemode==mode) { return(0); /*Drive already set*/ }/* The drive is not in the right mode, so we need to set it.*/ zero_cmd(cmd); cmd[0]=MODESELECT; /*Set drive transfer modes*//* cmd[1]=BLOCKPARAM; BLOCKPARAM==0*/ cmd[2]=mode; switch(mode) { case MODE_DATA: cmd[3]=0x08; /*2048 bytes*/ break; case MODE_USER: cmd[3]=0x09; /*2352 bytes*/ cmd[4]=0x30; break; case MODE_DA: cmd[3]=0x09; /*2352 bytes*/ cmd[4]=0x30; break; } i=0; while(retries-- > 0) { i=matcd_fastcmd(port,ldrive,cdrive,cmd); get_stat(port,ldrive); /*Read and toss status byte*/ if (i==0) { cd->drivemode=mode; /*Set new mode*/ return(i); } get_error(port,ldrive,cdrive); } cd->drivemode=MODE_UNKNOWN; /*We failed*/ return(i);}/*--------------------------------------------------------------------------- matcd_volinfo - Read information from disc Table of Contents---------------------------------------------------------------------------*/static int matcd_volinfo(int ldrive){ struct matcd_data *cd; int port,i; int z,cdrive; int retry; unsigned char cmd[MAXCMDSIZ]; unsigned char data[12]; retry=10; /*<16>This may take a long time*/ cd = &matcd_data[ldrive]; cdrive=ldrive&0x03; port=cd->iobase;#ifdef DEBUGOPEN printf("matcd%d: In volinfo, port %x\n",ldrive,port);#endif /*DEBUGOPEN*/ while(retry>0) { zero_cmd(cmd); cmd[0]=READDINFO; /*Read Disc Info*/ matcd_slowcmd(port,ldrive,cdrive,cmd); i=waitforit(10*TICKRES,DTEN,port,"matvinf"); if (i) { /*THIS SHOULD NOT HAPPEN*/ z=get_stat(port,ldrive);/*Read status byte*/ printf("matcd%d: command failed, status %x\n", ldrive,z); return(-1); } matcd_pread(port, 6, data); /*Read data returned*/ z=get_stat(port,ldrive);/*Read status byte*/#ifdef DEBUGOPEN printf("matcd%d: Data got was %x %x %x %x %x %x ",ldrive, data[0],data[1],data[2], data[3],data[4],data[5]); printf("status byte %x\n",z);#endif /*DEBUGOPEN*/ if ((z & MATCD_ST_ERROR)==0) break; /*No Error*//* If media change or other error, you have to read error data or the drive will reject subsequent commands.*/ if (chk_error(get_error(port, ldrive, cdrive))==ERR_FATAL) {#ifdef DEBUGOPEN printf("matcd%d: command failed, status %x\n", ldrive,z);#endif /*DEBUGOPEN*/ return(-1); } tsleep((caddr_t)&nextcontroller, PRIBIO, "matvi2", hz); if ((--retry)==0) return(-1);#ifdef DEBUGOPEN printf("matcd%d: Retrying",ldrive);#endif /*DEBUGOPEN*/ }#ifdef DEBUGOPEN printf("matcd%d: Status port %x \n",ldrive,inb(port+STATUS));#endif /*DEBUGOPEN*/ cd->volinfo.type=data[0]; cd->volinfo.trk_high=data[2]; cd->volinfo.trk_low=data[1]; cd->volinfo.vol_msf[0]=data[3]; cd->volinfo.vol_msf[1]=data[4]; cd->volinfo.vol_msf[2]=data[5]; if (cd->volinfo.trk_low + cd->volinfo.trk_high) { cd->flags |= MATCDLABEL; return(0); } return(-1);}/*--------------------------------------------------------------------------- blk_to_msf - Convert block numbers into CD disk block ids---------------------------------------------------------------------------*/static void blk_to_msf(int blk, unsigned char *msf){ blk=blk+150; /*2 seconds skip required to reach ISO data*/ msf[0]=blk/4500; blk=blk%4500; msf[1]=blk/75; msf[2]=blk%75; return;}/*--------------------------------------------------------------------------- msf_to_blk - Convert CD disk block ids into block numbers---------------------------------------------------------------------------*/static int msf_to_blk(unsigned char * cd){ return(((cd[0]*60) /*Convert MSF to*/ +cd[1])*75 /*Blocks minus 2*/ +cd[2]-150); /*seconds*/}/*--------------------------------------------------------------------------- matcd_blockread - Performs actual background disc I/O operations This routine is handed the block number to read, issues the command to the drive, waits for it to complete, reads the data or error, retries if needed, and returns the results to the host.---------------------------------------------------------------------------*/static void matcd_blockread(int state){ struct matcd_mbx *mbx; int ldrive,cdrive; int port, controller; short iftype; struct buf *bp; struct matcd_data *cd; int i; struct matcd_read2 rbuf; int blknum; caddr_t addr; int status; int errtyp; int phase; unsigned char cmd[MAXCMDSIZ]; mbx = &matcd_data[state & 0x0f].mbx; ldrive=mbx->ldrive; /*ldrive is logical drive #*/ cdrive=ldrive & 0x03; /*cdrive is drive # on a controller*/ port=mbx->port; /*port is base port for i/f*/ iftype=mbx->iftype; bp= mbx->bp; cd=&matcd_data[ldrive]; controller = cd->mbx.controller;#ifdef DEBUGIO printf("matcd%d: Show state %x cdrive %d partition %d\n", ldrive,state,cdrive,mbx->partition);#endif /*DEBUGIO*/loop:#ifdef DEBUGIO printf("matcd%d: Top dp %x\n",ldrive,(unsigned int)dp);#endif /*DEBUGIO*/ switch (state & 0xf0) { case MATCD_READ_1:#ifdef DEBUGIO printf("matcd%d: State 1 cd->flags %x\n",ldrive,cd->flags);#endif /*DEBUGIO*/ /* to check for raw/cooked mode */ if (cd->partflags[mbx->partition] & MATCDREADRAW) { mbx->sz = MATCDRBLK; i=matcd_setmode(ldrive, MODE_DA);#ifdef DEBUGIO printf("matcd%d: Set MODE_DA result %d\n",ldrive,i);#endif /*DEBUGIO*/ } else { mbx->sz = cd->blksize; i=matcd_setmode(ldrive, MODE_DATA);#ifdef DEBUGIO printf("matcd%d: Set MODE_DATA result %d\n",ldrive,i);#endif /*DEBUGIO*/ } /*for first block*/#ifdef DEBUGIO printf("matcd%d: A mbx %x bp %x b_bcount %x sz %x\n", ldrive,(unsigned int)mbx,(unsigned int)bp, (unsigned int)bp->b_bcount,mbx->sz);#endif /*DEBUGIO*/ mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz; mbx->skip=0;nextblock:#ifdef DEBUGIO printf("matcd%d: at Nextblock b_blkno %d\n", ldrive,(unsigned int)bp->b_blkno);#endif /*DEBUGIO*/ blknum=(bp->b_blkno / (mbx->sz/DEV_BSIZE)) + mbx->p_offset + mbx->skip/mbx->sz; blk_to_msf(blknum,rbuf.start_msf); zero_cmd(cmd); cmd[0]=READ; /*Get drive ID*/ cmd[1]=rbuf.start_msf[0]; cmd[2]=rbuf.start_msf[1]; cmd[3]=rbuf.start_msf[2]; cmd[6]=1; /*Xfer only one block*/ matcd_slowcmd(port,ldrive,cdrive,cmd);/* Now that we have issued the command, check immediately to see if data is ready. The drive has read-ahead caching, so it is possible the data is already in the drive buffer. If the data is not ready, schedule a wakeup and later on this code will run again to see if the data is ready then.*/ case MATCD_READ_2: state=MATCD_READ_2+ldrive; phase = (inb(port+STATUS)) & (DTEN|STEN);#ifdef DEBUGIO printf("matcd%d: In state 2 status %x ",ldrive,phase);#endif /*DEBUGIO*/ switch(phase) { case (DTEN|STEN): /*DTEN==H STEN==H*/#ifdef DEBUGIO printf("matcd%d: Sleeping\n",ldrive);#endif /*DEBUGIO*/ timeout((timeout_func_t)matcd_blockread,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -