📄 cbiolib.c
字号:
caddr_t ramAddr, /* where it is in memory (0 = malloc) */ size_t ramSize /* pool size */ ) { CBIO_DEV * pDev = NULL ; caddr_t pBase = NULL ; if( !cbioInstalled ) if( cbioLibInit() == ERROR ) goto error; if (ramSize != 0) { if( ramAddr == NULL ) pBase = malloc(ramSize ); else pBase = ramAddr ; if( pBase == NULL ) goto error ; } /* allocate and initialize the device control structure */ pDev = (CBIO_DEV *) objAlloc( cbioClassId ); if( pDev == NULL ) goto error; /* init Common fields */ if( semMInit( &pDev->cbio_mutex, cbioMutexSemOptions ) == ERROR) goto error ; pDev->cbio_readyChanged = FALSE ; pDev->params.cbio_lastErrBlk = NONE ; pDev->params.cbio_lastErrno = 0 ; pDev->cbio_memBase = pBase ; pDev->cbio_memSize = ramSize ; /* pointer to method functions needs to be filled later */ pDev->pFuncs = NULL ; /* make this object belong to its class */ objCoreInit (&pDev->objCore, cbioClassId); cbioRecentDev = pDev ; /* return device handle */ return( (CBIO_DEV_ID) pDev );error: if( pBase != NULL ) free (pBase); if( pDev != NULL ) free (pDev); return ( NULL ); }/********************************************************************************* shiftCalc - calculate how many shift bits** How many shifts <n< are needed such that <mask> == 1 << <N>* This is very useful for replacing multiplication with shifts,* where it is known a priori that the multiplier is 2^k.** RETURNS: Number of shifts.*/LOCAL int shiftCalc ( u_long mask ) { FAST i; for (i=0; i<32; i++) { if (mask & 1) break ; mask = mask >> 1 ; } return( i ); }/********************************************************************************* cbioWrapOk - dummy function returning OK**/LOCAL STATUS cbioWrapOk () { return OK; }/********************************************************************************* cbioBufCreate - create the local block buffer**/LOCAL STATUS cbioBufCreate ( CBIO_DEV_ID pDev ) { if( pDev->cbio_memBase != NULL && pDev->cbio_memSize != pDev->params.cbio_bytesPerBlk ) { /* block size may have changed */ free( pDev->cbio_memBase ); pDev->cbio_memBase = 0; pDev->cbio_memSize = 0; } if( pDev->cbio_memBase == NULL && pDev->cbio_memSize == 0 ) { pDev->cbio_memSize = pDev->params.cbio_bytesPerBlk ; pDev->cbio_memBase = malloc( pDev->cbio_memSize ); if( pDev->cbio_memBase == NULL ) { return ERROR; } /* Overload the block I/O function, better own the mutex here */ pDev->pFuncs->cbio_blkRW = blkWrapBlkRWbuf ; /* empty block */ pDev->cbio_blkNo = (u_long)NONE ; pDev->cbio_dirtyMask = 0; return OK; } else { errno = EINVAL; return ERROR; } }/********************************************************************************* blkWrapBlkRW - Read/Write blocks** Wrapper block Read/Write function calls the blkIo functions* directly, It does not deal with the tiny cache, and is used* only when there is no Tiny cache for by byte-wise operations.* When a tiny cache is installed, this function is overloaded* with the blkWrapBlkRWbuf function, which deals with Tiny cache* coherency and call this function subsequently.** This routine transfers between a user buffer and the lower layer * BLK_DEV. It is optimized for block transfers. ** dev - the CBIO handle of the device being accessed (from creation routine)* * start_block - the starting block of the transfer operation* * num_blocks - the total number of blocks to transfer* * buffer - address of the memory buffer used for the transfer* * rw - indicates the direction of transfer up or down (READ/WRITE)* * *cookie - pointer to cookie used by upper layer such as dosFsLib(),* it should be preserved.** RETURNS OK or ERROR and may otherwise set errno.*/LOCAL STATUS blkWrapBlkRW ( CBIO_DEV_ID dev, block_t start_block, block_t num_blocks, addr_t buffer, enum cbio_rw rw, cookie_t *cookie ) { CBIO_DEV * pDev = (void *) dev ; BLK_DEV * pBd = pDev->pDc ; STATUS stat = ERROR; int retryCount = 0 ;#ifdef DEBUG if( OBJ_VERIFY( dev, cbioClassId ) != OK) { INFO_MSG("blkWrapBlkRW: invalid handle\n",0,0,0,0,0,0); errno = S_objLib_OBJ_ID_ERROR; return ERROR; }#endifretry_loop: if( pBd->bd_readyChanged || dev->cbio_readyChanged ) { dev->cbio_readyChanged = TRUE ; errno = S_ioLib_DISK_NOT_PRESENT ; return ERROR; } if( start_block > pDev->params.cbio_nBlocks || (start_block+num_blocks) > pDev->params.cbio_nBlocks ) { errno = EINVAL; return ERROR; } switch( rw ) { case CBIO_READ: stat = pBd->bd_blkRd( pBd, start_block, num_blocks, buffer); break; case CBIO_WRITE: stat = pBd->bd_blkWrt( pBd, start_block, num_blocks, buffer); break; default: errno = S_ioLib_UNKNOWN_REQUEST; return ERROR; } /* record error if any */ if( stat == ERROR ) { pDev->params.cbio_lastErrBlk = start_block; pDev->params.cbio_lastErrno = errno ; if( errno == S_ioLib_DISK_NOT_PRESENT ) dev->cbio_readyChanged = TRUE; /* some block drivers dont do retires relying on old dosFs for that */ if( (blkWrapIoctl( pDev, CBIO_STATUS_CHK, 0) == OK) && ( retryCount++ < pBd->bd_retry )) { int tick = tickGet(); /* if device was not obviously replaced, try to reset it */ if( !( pBd->bd_readyChanged || dev->cbio_readyChanged) ) { if( pBd->bd_reset != NULL ) pBd->bd_reset( pBd ); do { if( blkWrapIoctl( pDev, CBIO_STATUS_CHK, 0) == OK) goto retry_loop; taskDelay(5); } while( tickGet() < (UINT32) tick+sysClkRateGet() ) ; } } } return stat; }/********************************************************************************* blkWrapBlkRWbuf - wrapper block I/O for coherency with tiny cache** This routine transfers between a user buffer and the lower layer BLK_DEV* It is optimized for block transfers. ** dev - the CBIO handle of the device being accessed (from creation routine)* * start_block - the starting block of the transfer operation* * num_blocks - the total number of blocks to transfer* * buffer - address of the memory buffer used for the transfer* * rw - indicates the direction of transfer up or down (READ/WRITE)* * *cookie - pointer to cookie used by upper layer such as dosFsLib(),* it should be preserved.** RETURNS OK or ERROR and may otherwise set errno.*/LOCAL STATUS blkWrapBlkRWbuf ( CBIO_DEV_ID dev, block_t start_block, block_t num_blocks, addr_t buffer, enum cbio_rw rw, cookie_t *cookie ) { FAST CBIO_DEV * pDev = dev ; STATUS stat = OK ; if( semTake( &pDev->cbio_mutex, WAIT_FOREVER) == ERROR ) return ERROR; /* verify that there is a block buffer, if not, allocate one */ if( pDev->cbio_memBase == NULL) { if( cbioBufCreate( pDev) == ERROR ) { semGive(&pDev->cbio_mutex); return ERROR; } } /* see if Tiny Cache contains a valid block */ if( pDev->cbio_blkNo != (u_long) NONE ) { /* see if the range touches the cached block */ if( (pDev->cbio_blkNo >= start_block) && (pDev->cbio_blkNo < start_block+num_blocks) ) { /* flush the current contents of the block buffer if dirty */ if( pDev->cbio_dirtyMask != 0 ) { block_t cachedBlock = pDev->cbio_blkNo ; pDev->cbio_blkNo = NONE ; pDev->cbio_dirtyMask = 0; stat = blkWrapBlkRW( pDev, cachedBlock, 1, pDev->cbio_memBase, CBIO_WRITE, NULL); } else { /* else just forget about it */ pDev->cbio_blkNo = NONE ; } } } if( stat == ERROR ) return stat; stat = blkWrapBlkRW (dev, start_block, num_blocks, buffer, rw, cookie) ; semGive(&pDev->cbio_mutex); return stat ; }/********************************************************************************* blkWrapBytesRW - Read/Write bytes** In order to implement the byte-wise read/write operation, a tiny* cache is implemented, which is used to store block data on which* byte operations are performed.** The tiny cache is a single disk block sized buffer at this time* which should suffice for solid-state (e.g. Flash) disks to be used* without the real disk cache, meaning dosFsLib directly on top of* this wrapper.** This routine transfers between a user buffer and the lower layer BLK_DEV* It is optimized for byte transfers. ** dev - the CBIO handle of the device being accessed (from creation routine)* * start_block - the starting block of the transfer operation* * offset - offset in bytes from the beginning of the starting block* * buffer - address of the memory buffer used for the transfer* * nBytes - number of bytes to transfer* * rw - indicates the direction of transfer up or down (READ/WRITE)* * *cookie - pointer to cookie used by upper layer such as dosFsLib(),* it should be preserved.* * RETURNS OK or ERROR and may otherwise set errno.*/LOCAL STATUS blkWrapBytesRW ( CBIO_DEV_ID dev, block_t start_block, off_t offset, addr_t buffer, size_t nBytes, enum cbio_rw rw, cookie_t *cookie ) { CBIO_DEV * pDev = dev ; BLK_DEV * pBd = pDev->pDc ; STATUS stat = OK ; caddr_t pStart; if( pBd->bd_readyChanged || dev->cbio_readyChanged ) { dev->cbio_readyChanged = TRUE ; errno = S_ioLib_DISK_NOT_PRESENT ; return ERROR; } if( start_block >= pDev->params.cbio_nBlocks ) { errno = EINVAL; return ERROR; } /* verify that all bytes are within one block range */ if (((offset + nBytes) > pDev->params.cbio_bytesPerBlk ) || (offset <0) || (nBytes <=0)) { errno = EINVAL; return ERROR; } if( semTake( &pDev->cbio_mutex, WAIT_FOREVER) == ERROR ) return ERROR; /* verify that there is a block buffer, if not, allocate one */ if( pDev->cbio_memBase == NULL) { if( cbioBufCreate( pDev) == ERROR ) { semGive(&pDev->cbio_mutex); return ERROR; } } /* flush the current contents of the block buffer if needed */ if( pDev->cbio_blkNo != (u_long)NONE && pDev->cbio_blkNo != start_block && pDev->cbio_dirtyMask != 0 ) { block_t cachedBlock = pDev->cbio_blkNo ; pDev->cbio_blkNo = NONE ; pDev->cbio_dirtyMask = 0; stat = blkWrapBlkRW( pDev, cachedBlock, 1, pDev->cbio_memBase, CBIO_WRITE, NULL); if( stat == ERROR ) { semGive(&pDev->cbio_mutex); return ERROR; } } /* get the requested block into cache */ if( start_block != pDev->cbio_blkNo && pDev->cbio_dirtyMask == 0 ) { stat = blkWrapBlkRW( pDev, start_block, 1, pDev->cbio_memBase, CBIO_READ, NULL); if( stat == ERROR ) { semGive(&pDev->cbio_mutex); return ERROR; } pDev->cbio_blkNo = start_block ; pDev->cbio_dirtyMask = 0; } assert( start_block == pDev->cbio_blkNo ); /* calculate actual memory address of data */ pStart = pDev->cbio_memBase + offset ;#ifdef DEBUG if(cbioDebug > 1) logMsg("blkWrapBytesRW: blk %d + %d # %d bytes -> addr %x, %x bytes\n", start_block, offset, nBytes, (int) pStart, nBytes, 0);#endif switch( rw ) { case CBIO_READ: bcopy( pStart, buffer, nBytes ); break; case CBIO_WRITE: bcopy( buffer, pStart, nBytes ); pDev->cbio_dirtyMask = 1; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -