// mcd_SwitchOperationTo // ----------------------------------------------------------------------------- /// Switch MCD id. /// /// To be called when appliction switch to another t-falsh. /// @param mcdId is mcd device identification under dual t-flash mode.value is 0 or 1. /// // ============================================================================= PUBLIC MCD_ERR_T mcd_SwitchOperationTo(MCD_CARD_ID mcdId) { MCD_CONFIG_STRUCT_T* mcd_config = NULL; MCD_ERR_T mcd_err = MCD_ERR_NO; UINT32 config_id; MCD_CARD_ID card_id; card_id = mcdId; mcd_config = (MCD_CONFIG_STRUCT_T*)tgt_GetMcdConfig(); config_id = mcdId == MCD_CARD_ID_0 ? 0:1; mcd_WaitSemTFlash(); if(MCD_CONFIG_CARD_TYPE_SPI == mcd_config->mcd_if[0].type && MCD_CONFIG_CARD_TYPE_SPI == mcd_config->mcd_if[1].type) { mcd_err = mcd_spi_SwitchOperationTo(mcdId); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_SwitchOperationTo:spi switch.mcdId = %d, mcd_err = %d.",mcdId,mcd_err); } else { mcd_err = MCD_ERR_NO; } if(MCD_ERR_NO == mcd_err) { g_mcd_id = mcdId; MCD_TRACE(MCD_INFO_TRC, 0, "mcd_SwitchOperationTo:g_mcd_id = %d.",g_mcd_id); // al_HstSendEvent(0xdada0000|g_mcd_id); } mcd_ReleaseSemTFlash(); return mcd_err; }
PUBLIC MCD_ERR_T mcd_Close(MCD_CARD_ID mcdId) { MCD_CONFIG_STRUCT_T* mcd_config = NULL; UINT32 config_id = 0; //MCD_ERR_T mcd_err[2]= {MCD_ERR_NO,MCD_ERR_NO}; MCD_ERR_T mcd_err = MCD_ERR_NO; mcd_config = (MCD_CONFIG_STRUCT_T*)tgt_GetMcdConfig(); config_id = mcdId == MCD_CARD_ID_0 ? 0:1; mcd_WaitSemTFlash(); if(MCD_CONFIG_CARD_TYPE_SDMMC == mcd_config->mcd_if[config_id].type) { if(1 == g_IsOpen[config_id]) { // hal_HstSendEvent(0xb10000b0); mcd_err = mcd_sdmmc_Close(); // hal_HstSendEvent(0xb100b000 | mcd_err); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Close(%d):(sdmmc)mcd_err = %d.",mcdId,mcd_err); } else { // hal_HstSendEvent(0xb10000b1); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Close(%d):g_IsOpen[%d] == 0 ",mcdId,config_id); } } else if(MCD_CONFIG_CARD_TYPE_SPI == mcd_config->mcd_if[config_id].type) { if(1 == g_IsOpen[config_id]) { // hal_HstSendEvent(0xb20000b0); mcd_err = mcd_spi_Close(); // hal_HstSendEvent(0xb200b000 | mcd_err); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Close(%d):(spi)mcd_err = %d.",mcdId,mcd_err); } else { // hal_HstSendEvent(0xb20000b1); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Close(%d):g_IsOpen[%d] == 0 ",mcdId,config_id); } } else { mcd_err = MCD_ERR_NO_CARD; } if(mcd_err == MCD_ERR_NO) { g_IsOpen[config_id] = 0; } mcd_ReleaseSemTFlash(); return mcd_err;//mcd_err[config_id]; }
// mcd_Read // ----------------------------------------------------------------------------- /// Read using pattern mode. /// @param startAddr: of the MMC memory block where the data /// will be read /// @param blockRd Pointer to the buffer where the data will be stored. Must be aligned /// on a 32 bits boundary. /// @param size Number of bytes to read. Must be an interger multiple of the /// sector size of the card. // ============================================================================= PUBLIC MCD_ERR_T mcd_Read(UINT32 startAddr, UINT8* blockRd, UINT32 size) { MCD_CONFIG_STRUCT_T* mcd_config = NULL; UINT32 config_id = 0; UINT32 i; MCD_ERR_T mcd_err = MCD_ERR_NO; mcd_config = (MCD_CONFIG_STRUCT_T*)tgt_GetMcdConfig(); mcd_WaitSemTFlash(); config_id = g_mcd_id == MCD_CARD_ID_0 ? 0:1; if(0 == g_IsOpen[config_id] ) { MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Read:g_IsOpen is 0,addr = 0x%x.",startAddr); mcd_ReleaseSemTFlash(); return MCD_ERR_NO_CARD; } if(MCD_CONFIG_CARD_TYPE_SDMMC == mcd_config->mcd_if[config_id].type) { mcd_err = mcd_sdmmc_Read(startAddr, blockRd, size); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Read:mult-block,config_id = %d,mcd_err = %d,startAddr = 0x%x,size = 0x%x.",config_id,mcd_err,startAddr,size); } else if(MCD_CONFIG_CARD_TYPE_SPI == mcd_config->mcd_if[config_id].type) { for(i = 0; i < (size/MCD_DEFUALT_BLOCK_SIZE); i++) { // hal_HstSendEvent(0xc0000000 | (startAddr + i*MCD_DEFUALT_BLOCK_SIZE)); mcd_err = mcd_spi_Read((startAddr + i*MCD_DEFUALT_BLOCK_SIZE), (blockRd + i*MCD_DEFUALT_BLOCK_SIZE), MCD_DEFUALT_BLOCK_SIZE); if(MCD_ERR_NO != mcd_err) { break; } MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Read:sigle-block,config_id = %d,mcd_err = %d,startAddr = 0x%x,512.",config_id,mcd_err,(startAddr + i*MCD_DEFUALT_BLOCK_SIZE)); } } else { mcd_err = MCD_ERR_NO_CARD; } if(MCD_ERR_NO != mcd_err) { MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Read:sigle-block,config_id = %d,mcd_err = %d,startAddr = 0x%x,size = 0x%x.",config_id,mcd_err,startAddr,size); // hal_HstSendEvent(0xc00000e1); // hal_HstSendEvent(mcd_err); } mcd_ReleaseSemTFlash(); return mcd_err; }
PUBLIC VOID mcd_LowPower(VOID) { if((0 == g_IsOpen[0]) && (0 == g_IsOpen[1])) { MCD_TRACE(MCD_INFO_TRC, 0, "mcd_LowPower ok."); pmd_EnablePower(PMD_POWER_SDMMC, FALSE); mcd_delay(1638); } else { MCD_TRACE(MCD_INFO_TRC, 0, "mcd_LowPower tflas card not close. t0 = %d, t1= %d.",g_IsOpen[0],g_IsOpen[1]); } }
void mcdstart(struct mcd_softc *sc) { struct buf *bp; int s; loop: s = splbio(); if ((bp = bufq_get(sc->buf_queue)) == NULL) { /* Nothing to do. */ sc->active = 0; splx(s); return; } /* Block found to process. */ MCD_TRACE("start: found block bp=0x%p\n", bp); splx(s); /* Changed media? */ if ((sc->flags & MCDF_LOADED) == 0) { MCD_TRACE("start: drive not valid%s", "\n"); bp->b_error = EIO; biodone(bp); goto loop; } sc->active = 1; /* Instrumentation. */ s = splbio(); disk_busy(&sc->sc_dk); splx(s); sc->mbx.retry = MCD_RDRETRIES; sc->mbx.bp = bp; sc->mbx.blkno = bp->b_rawblkno; sc->mbx.nblk = bp->b_bcount / sc->blksize; sc->mbx.sz = sc->blksize; sc->mbx.skip = 0; sc->mbx.state = MCD_S_BEGIN; sc->mbx.mode = MCD_MD_COOKED; s = splbio(); (void) mcdintr(sc); splx(s); }
int mcdclose(dev_t dev, int flag, int fmt, struct lwp *l) { struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); int part = MCDPART(dev); MCD_TRACE("close: partition=%d\n", part); mutex_enter(&sc->sc_lock); switch (fmt) { case S_IFCHR: sc->sc_dk.dk_copenmask &= ~(1 << part); break; case S_IFBLK: sc->sc_dk.dk_bopenmask &= ~(1 << part); break; } sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; if (sc->sc_dk.dk_openmask == 0) { /* XXXX Must wait for I/O to complete! */ #if 0 (void) mcd_setmode(sc, MCD_MD_SLEEP); #endif (void) mcd_setlock(sc, MCD_LK_UNLOCK); } mutex_exit(&sc->sc_lock); return 0; }
PUBLIC MCD_ERR_T mcd_Open(MCD_CARD_ID mcdId,MCD_CSD_T* mcdCsd, MCD_CARD_VER mcdVer) { MCD_CONFIG_STRUCT_T* mcd_config = NULL; UINT32 config_id = 0; MCD_ERR_T mcd_err = MCD_ERR_NO; mcd_config = (MCD_CONFIG_STRUCT_T*)tgt_GetMcdConfig(); config_id = (mcdId == MCD_CARD_ID_0) ? 0:1; mcd_WaitSemTFlash(); g_mcd_id = mcdId; if(MCD_CONFIG_CARD_TYPE_SDMMC == mcd_config->mcd_if[config_id].type) { if(0 == g_IsOpen[config_id]) { // hal_HstSendEvent(0xa10000a0); mcd_err = mcd_sdmmc_Open(mcdCsd,mcdVer,&mcd_config->mcd_if[config_id]); // hal_HstSendEvent(0xa100a000 | mcd_err); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Open(%d):(sdmmc)mcd_err = %d.",mcdId,mcd_err); } } else if(MCD_CONFIG_CARD_TYPE_SPI == mcd_config->mcd_if[config_id].type) { if(0 == g_IsOpen[config_id]) { // hal_HstSendEvent(0xa20000a0); mcd_err = mcd_spi_Open(mcdCsd,mcdVer,&mcd_config->mcd_if[config_id]); //hal_HstSendEvent(0xa200a000 | mcd_err); MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Open(%d):(spi)mcd_err = %d.",mcdId,mcd_err); } } else { mcd_err = MCD_ERR_NO_CARD; } if(MCD_ERR_NO == mcd_err) { g_IsOpen[config_id] = 1; } MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Open():config_id = %d,mcd_err = %d,mcdVer = %d.",config_id,mcd_err,mcdVer); mcd_ReleaseSemTFlash(); return mcd_err; }
static int mcd_setflags(struct mcd_softc *sc) { /* check flags */ if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) || !(sc->data.status & MCDDSKIN)) { MCD_TRACE("setflags: sensed DSKCHNG or DOOROPEN or !DSKIN\n"); mcd_soft_reset(sc); return (-1); } if (sc->data.status & MCDAUDIOBSY) sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS; else if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) sc->data.audio_status = CD_AS_PLAY_COMPLETED; return (0); }
// mcd_GetCardSize // ----------------------------------------------------------------------------- /// Get card size /// /// @param size Structure use to store size of memory card // ============================================================================= PUBLIC MCD_ERR_T mcd_GetCardSize(MCD_CARD_SIZE_T* size) { MCD_CONFIG_STRUCT_T* mcd_config = NULL; MCD_CARD_SIZE_T mcd_size = {0,0}; UINT32 config_id = 0; MCD_ERR_T mcd_err = MCD_ERR_NO; mcd_config = (MCD_CONFIG_STRUCT_T*)tgt_GetMcdConfig(); mcd_WaitSemTFlash(); config_id = g_mcd_id == MCD_CARD_ID_0 ? 0:1; if(MCD_CONFIG_CARD_TYPE_SDMMC == mcd_config->mcd_if[config_id].type) { mcd_err = mcd_sdmmc_GetCardSize(&mcd_size); // hal_HstSendEvent(0xba000000 | mcd_err); // hal_HstSendEvent(size->nbBlock); } else if(MCD_CONFIG_CARD_TYPE_SPI == mcd_config->mcd_if[config_id].type) { mcd_err = mcd_spi_GetCardSize(&mcd_size); // hal_HstSendEvent(0xbb000000 | mcd_err); // hal_HstSendEvent(size->nbBlock); } else { mcd_err = MCD_ERR_NO_CARD; } size->nbBlock = ((mcd_size.nbBlock/512)*mcd_size.blockLen); size->blockLen = mcd_size.blockLen > 0 ?512:0; MCD_TRACE(MCD_INFO_TRC, 0, "mcd_GetCardSize():config_id = %d,mcd_err = %d,blk_nr = 0x%x,blk_sz = 0x%x.",config_id,mcd_err,size->nbBlock,size->blockLen); mcd_ReleaseSemTFlash(); return mcd_err; }
PUBLIC MCD_ERR_T mcd_Close(VOID) { MCD_CONFIG_STRUCT_T* mcd_config = NULL; UINT32 config_id = 0; MCD_ERR_T mcd_err = MCD_ERR_NO; mcd_config = (MCD_CONFIG_STRUCT_T*)tgt_GetMcdConfig(); mcd_WaitSemTFlash(); if(MCD_CONFIG_CARD_TYPE_SDMMC == mcd_config->mcd_if[config_id].type) { if(1 == g_IsOpen) { mcd_err = mcd_sdmmc_Close(); } } else if(MCD_CONFIG_CARD_TYPE_SPI == mcd_config->mcd_if[config_id].type) { if(1 == g_IsOpen) { mcd_err = mcd_spi_Close(); } } else { mcd_err = MCD_ERR_NO_CARD; } if(MCD_ERR_NO == mcd_err) { g_IsOpen = 0; } MCD_TRACE(MCD_INFO_TRC, 0, "mcd_Close():config_id = %d,mcd_err = %d.",config_id,mcd_err); mcd_ReleaseSemTFlash(); return mcd_err; }
static void mcd_doread(struct mcd_softc *sc, int state, struct mcd_mbx *mbxin) { struct mcd_mbx *mbx; struct bio *bp; int rm, i, k; struct mcd_read2 rbuf; int blknum; caddr_t addr; mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin; bp = mbx->bp; loop: switch (state) { case MCD_S_BEGIN: mbx = sc->ch_mbxsave = mbxin; case MCD_S_BEGIN1: retry_status: /* get status */ MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT); mbx->count = RDELAY_WAITSTAT; sc->ch_state = MCD_S_WAITSTAT; sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ return; case MCD_S_WAITSTAT: sc->ch_state = MCD_S_WAITSTAT; untimeout(mcd_timeout,(caddr_t)sc, sc->ch); if (mbx->count-- >= 0) { if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { sc->ch_state = MCD_S_WAITSTAT; timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ return; } sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; if (sc->data.status & MCD_ST_CMDCHECK) goto retry_status; if (mcd_setflags(sc) < 0) goto changed; MCD_TRACE("got WAITSTAT delay=%d\n", RDELAY_WAITSTAT-mbx->count); /* reject, if audio active */ if (sc->data.status & MCDAUDIOBSY) { device_printf(sc->dev, "audio is active\n"); goto readerr; } retry_mode: /* to check for raw/cooked mode */ if (sc->data.flags & MCDREADRAW) { rm = MCD_MD_RAW; mbx->sz = MCDRBLK; } else { rm = MCD_MD_COOKED; mbx->sz = sc->data.blksize; } if (rm == sc->data.curr_mode) goto modedone; mbx->count = RDELAY_WAITMODE; sc->data.curr_mode = MCD_MD_UNKNOWN; mbx->mode = rm; MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE); MCD_WRITE(sc, MCD_REG_COMMAND, rm); sc->ch_state = MCD_S_WAITMODE; sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ return; } else { device_printf(sc->dev, "timeout getstatus\n"); goto readerr; } case MCD_S_WAITMODE: sc->ch_state = MCD_S_WAITMODE; untimeout(mcd_timeout, (caddr_t)sc, sc->ch); if (mbx->count-- < 0) { device_printf(sc->dev, "timeout set mode\n"); goto readerr; } if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) { sc->ch_state = MCD_S_WAITMODE; sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); return; } sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; if (sc->data.status & MCD_ST_CMDCHECK) { sc->data.curr_mode = MCD_MD_UNKNOWN; goto retry_mode; } if (mcd_setflags(sc) < 0) goto changed; sc->data.curr_mode = mbx->mode; MCD_TRACE("got WAITMODE delay=%d\n", RDELAY_WAITMODE-mbx->count); modedone: /* for first block */ mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz; mbx->skip = 0; nextblock: blknum = (bp->bio_blkno / (mbx->sz/DEV_BSIZE)) + mbx->skip/mbx->sz; MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n", blknum, bp); /* build parameter block */ hsg2msf(blknum,rbuf.start_msf); retry_read: /* send the read command */ critical_enter(); MCD_WRITE(sc, MCD_REG_COMMAND, sc->data.read_command); MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[0]); MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[1]); MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[2]); MCD_WRITE(sc, MCD_REG_COMMAND, 0); MCD_WRITE(sc, MCD_REG_COMMAND, 0); MCD_WRITE(sc, MCD_REG_COMMAND, 1); critical_exit(); /* Spin briefly (<= 2ms) to avoid missing next block */ for (i = 0; i < 20; i++) { k = MCD_READ(sc, MCD_FLAGS); if (!(k & MFL_DATA_NOT_AVAIL)) goto got_it; DELAY(100); } mbx->count = RDELAY_WAITREAD; sc->ch_state = MCD_S_WAITREAD; sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ return; case MCD_S_WAITREAD: sc->ch_state = MCD_S_WAITREAD; untimeout(mcd_timeout, (caddr_t)sc, sc->ch); if (mbx->count-- > 0) { k = MCD_READ(sc, MCD_FLAGS); if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */ MCD_TRACE("got data delay=%d\n", RDELAY_WAITREAD-mbx->count); got_it: /* data is ready */ addr = bp->bio_data + mbx->skip; MCD_WRITE(sc, MCD_REG_CTL2,0x04); /* XXX */ for (i=0; i<mbx->sz; i++) *addr++ = MCD_READ(sc, MCD_REG_RDATA); MCD_WRITE(sc, MCD_REG_CTL2,0x0c); /* XXX */ k = MCD_READ(sc, MCD_FLAGS); /* If we still have some junk, read it too */ if (!(k & MFL_DATA_NOT_AVAIL)) { MCD_WRITE(sc, MCD_REG_CTL2, 0x04); /* XXX */ (void)MCD_READ(sc, MCD_REG_RDATA); (void)MCD_READ(sc, MCD_REG_RDATA); MCD_WRITE(sc, MCD_REG_CTL2, 0x0c); /* XXX */ } if (--mbx->nblk > 0) { mbx->skip += mbx->sz; goto nextblock; } /* return buffer */ bp->bio_resid = 0; biodone(bp); sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); mcd_start(sc); return; } if (!(k & MFL_STATUS_NOT_AVAIL)) { sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF; if (sc->data.status & MCD_ST_CMDCHECK) goto retry_read; if (mcd_setflags(sc) < 0) goto changed; } sc->ch_state = MCD_S_WAITREAD; sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */ return; } else { device_printf(sc->dev, "timeout read data\n"); goto readerr; } } readerr: if (mbx->retry-- > 0) { device_printf(sc->dev, "retrying\n"); state = MCD_S_BEGIN1; goto loop; } harderr: /* invalidate the buffer */ bp->bio_flags |= BIO_ERROR; bp->bio_resid = bp->bio_bcount; biodone(bp); sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW); mcd_start(sc); return; changed: device_printf(sc->dev, "media changed\n"); goto harderr; #ifdef NOTDEF device_printf(sc->dev, "unit timeout, resetting\n"); MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET); DELAY(300000); (void)mcd_getstat(sc, 1); (void)mcd_getstat(sc, 1); /*sc->data.status &= ~MCDDSKCHNG; */ sc->data.debug = 1; /* preventive set debug mode */ #endif }
static int mcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { struct mcd_softc *sc; int retry,r; sc = (struct mcd_softc *)dev->si_drv1; if (mcd_getstat(sc, 1) == -1) /* detect disk change too */ return (EIO); MCD_TRACE("ioctl called 0x%lx\n", cmd); switch (cmd) { case CDIOCSETPATCH: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTERIO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: return (EINVAL); case CDIOCEJECT: return mcd_eject(sc); case CDIOCSETDEBUG: sc->data.debug = 1; return (0); case CDIOCCLRDEBUG: sc->data.debug = 0; return (0); case CDIOCRESET: return mcd_hard_reset(sc); case CDIOCALLOW: return mcd_lock_door(sc, MCD_LK_UNLOCK); case CDIOCPREVENT: return mcd_lock_door(sc, MCD_LK_LOCK); case CDIOCCLOSE: return mcd_inject(sc); } if (!(sc->data.flags & MCDVALID)) { if ( (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN)) || !(sc->data.status & MCDDSKIN)) for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) { (void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC); if ((r = mcd_getstat(sc, 1)) == -1) return (EIO); if (r != -2) break; } if ( (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG)) || !(sc->data.status & MCDDSKIN) || mcdsize(dev) < 0 ) return (ENXIO); sc->data.flags |= MCDVALID; sc->data.partflags |= MCDREADRAW; (void) mcd_lock_door(sc, MCD_LK_LOCK); if (!(sc->data.flags & MCDVALID)) return (ENXIO); } switch (cmd) { case DIOCGMEDIASIZE: *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; return (0); break; case DIOCGSECTORSIZE: *(u_int *)addr = sc->data.blksize; return (0); break; case CDIOCPLAYTRACKS: return mcd_playtracks(sc, (struct ioc_play_track *) addr); case CDIOCPLAYBLOCKS: return mcd_playblocks(sc, (struct ioc_play_blocks *) addr); case CDIOCPLAYMSF: return mcd_playmsf(sc, (struct ioc_play_msf *) addr); case CDIOCREADSUBCHANNEL: return mcd_subchan(sc, (struct ioc_read_subchannel *) addr); case CDIOREADTOCHEADER: return mcd_toc_header(sc, (struct ioc_toc_header *) addr); case CDIOREADTOCENTRYS: return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr); case CDIOCRESUME: return mcd_resume(sc); case CDIOCPAUSE: return mcd_pause(sc); case CDIOCSTART: if (mcd_setmode(sc, MCD_MD_COOKED) != 0) return (EIO); return (0); case CDIOCSTOP: return mcd_stop(sc); default: return (ENOTTY); } /*NOTREACHED*/ }
int mcdopen(dev_t dev, int flag, int fmt, struct lwp *l) { int error, part; struct mcd_softc *sc; sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); if (sc == NULL) return ENXIO; mutex_enter(&sc->sc_lock); if (sc->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, * disallow further opens. */ if ((sc->flags & MCDF_LOADED) == 0) { error = EIO; goto bad3; } } else { /* * Lock the drawer. This will also notice any pending disk * change or door open indicator and clear the MCDF_LOADED bit * if necessary. */ (void) mcd_setlock(sc, MCD_LK_LOCK); if ((sc->flags & MCDF_LOADED) == 0) { /* Partially reset the state. */ sc->lastmode = MCD_MD_UNKNOWN; sc->lastupc = MCD_UPC_UNKNOWN; sc->flags |= MCDF_LOADED; /* Set the mode, causing the disk to spin up. */ if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) goto bad2; /* Load the physical device parameters. */ if (mcd_get_parms(sc) != 0) { error = ENXIO; goto bad2; } /* Read the table of contents. */ if ((error = mcd_read_toc(sc)) != 0) goto bad2; /* Fabricate a disk label. */ mcdgetdisklabel(sc); } } part = MCDPART(dev); MCD_TRACE("open: partition=%d disksize=%ld blksize=%d\n", part, sc->disksize, sc->blksize); /* Check that the partition exists. */ if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions || sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { error = ENXIO; goto bad; } /* Insure only one open at a time. */ switch (fmt) { case S_IFCHR: sc->sc_dk.dk_copenmask |= (1 << part); break; case S_IFBLK: sc->sc_dk.dk_bopenmask |= (1 << part); break; } sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; mutex_exit(&sc->sc_lock); return 0; bad2: sc->flags &= ~MCDF_LOADED; bad: if (sc->sc_dk.dk_openmask == 0) { #if 0 (void) mcd_setmode(sc, MCD_MD_SLEEP); #endif (void) mcd_setlock(sc, MCD_LK_UNLOCK); } bad3: mutex_exit(&sc->sc_lock); return error; }
int mcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev)); int error; int part; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif MCD_TRACE("ioctl: cmd=0x%lx\n", cmd); if ((sc->flags & MCDF_LOADED) == 0) return EIO; error = disk_ioctl(&sc->sc_dk, dev, cmd, addr, flag, l); if (error != EPASSTHROUGH) return error; part = MCDPART(dev); switch (cmd) { case DIOCWDINFO: case DIOCSDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: case ODIOCSDINFO: #endif { struct disklabel *lp; if ((flag & FWRITE) == 0) return EBADF; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, addr, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = addr; mutex_enter(&sc->sc_lock); sc->flags |= MCDF_LABELLING; error = setdisklabel(sc->sc_dk.dk_label, lp, /*sc->sc_dk.dk_openmask : */0, sc->sc_dk.dk_cpulabel); if (error == 0) { } sc->flags &= ~MCDF_LABELLING; mutex_exit(&sc->sc_lock); return error; } case DIOCWLABEL: return EBADF; case DIOCGDEFLABEL: mcdgetdefaultlabel(sc, addr); return 0; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDEFLABEL: mcdgetdefaultlabel(sc, &newlabel); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &newlabel, sizeof (struct olddisklabel)); return 0; #endif case CDIOCPLAYTRACKS: return mcd_playtracks(sc, addr); case CDIOCPLAYMSF: return mcd_playmsf(sc, addr); case CDIOCPLAYBLOCKS: return mcd_playblocks(sc, addr); case CDIOCREADSUBCHANNEL: { struct cd_sub_channel_info info; error = mcd_read_subchannel(sc, addr, &info); if (error != 0) { struct ioc_read_subchannel *ch = addr; error = copyout(&info, ch->data, ch->data_len); } return error; } case CDIOCREADSUBCHANNEL_BUF: return mcd_read_subchannel(sc, addr, &((struct ioc_read_subchannel_buf *)addr)->info); case CDIOREADTOCHEADER: return mcd_toc_header(sc, addr); case CDIOREADTOCENTRYS: { struct cd_toc_entry entries[MCD_MAXTOCS]; struct ioc_read_toc_entry *te = addr; int count; if (te->data_len > sizeof entries) return EINVAL; error = mcd_toc_entries(sc, te, entries, &count); if (error == 0) /* Copy the data back. */ error = copyout(entries, te->data, min(te->data_len, count * sizeof(struct cd_toc_entry))); return error; } case CDIOREADTOCENTRIES_BUF: { struct ioc_read_toc_entry_buf *te = addr; int count; if (te->req.data_len > sizeof te->entry) return EINVAL; return mcd_toc_entries(sc, &te->req, te->entry, &count); } case CDIOCSETPATCH: case CDIOCGETVOL: case CDIOCSETVOL: case CDIOCSETMONO: case CDIOCSETSTEREO: case CDIOCSETMUTE: case CDIOCSETLEFT: case CDIOCSETRIGHT: return EINVAL; case CDIOCRESUME: return mcd_resume(sc); case CDIOCPAUSE: return mcd_pause(sc); case CDIOCSTART: return EINVAL; case CDIOCSTOP: return mcd_stop(sc); case DIOCEJECT: if (*(int *)addr == 0) { /* * Don't force eject: check that we are the only * partition open. If so, unlock it. */ if ((sc->sc_dk.dk_openmask & ~(1 << part)) == 0 && sc->sc_dk.dk_bopenmask + sc->sc_dk.dk_copenmask == sc->sc_dk.dk_openmask) { error = mcd_setlock(sc, MCD_LK_UNLOCK); if (error) return (error); } else { return (EBUSY); } } /* FALLTHROUGH */ case CDIOCEJECT: /* FALLTHROUGH */ case ODIOCEJECT: return mcd_eject(sc); case CDIOCALLOW: return mcd_setlock(sc, MCD_LK_UNLOCK); case CDIOCPREVENT: return mcd_setlock(sc, MCD_LK_LOCK); case DIOCLOCK: return mcd_setlock(sc, (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK); case CDIOCSETDEBUG: sc->debug = 1; return 0; case CDIOCCLRDEBUG: sc->debug = 0; return 0; case CDIOCRESET: return mcd_hard_reset(sc); default: return ENOTTY; } #ifdef DIAGNOSTIC panic("mcdioctl: impossible"); #endif }
void mcdstrategy(struct buf *bp) { struct mcd_softc *sc; struct disklabel *lp; daddr_t blkno; int s; sc = device_lookup_private(&mcd_cd, MCDUNIT(bp->b_dev)); lp = sc->sc_dk.dk_label; /* Test validity. */ MCD_TRACE("strategy: buf=0x%p blkno=%d bcount=%d\n", bp, (int) bp->b_blkno, bp->b_bcount); if (bp->b_blkno < 0 || (bp->b_bcount % sc->blksize) != 0) { printf("%s: strategy: blkno = %" PRId64 " bcount = %d\n", device_xname(sc->sc_dev), bp->b_blkno, bp->b_bcount); bp->b_error = EINVAL; goto done; } /* If device invalidated (e.g. media change, door open), error. */ if ((sc->flags & MCDF_LOADED) == 0) { MCD_TRACE("strategy: drive not valid%s", "\n"); bp->b_error = EIO; goto done; } /* No data to read. */ if (bp->b_bcount == 0) goto done; /* * Do bounds checking, adjust transfer. if error, process. * If end of partition, just return. */ if (MCDPART(bp->b_dev) != RAW_PART && bounds_check_with_label(&sc->sc_dk, bp, (sc->flags & (MCDF_WLABEL|MCDF_LABELLING)) != 0) <= 0) goto done; /* * Now convert the block number to absolute and put it in * terms of the device's logical block size. */ blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); if (MCDPART(bp->b_dev) != RAW_PART) blkno += lp->d_partitions[MCDPART(bp->b_dev)].p_offset; bp->b_rawblkno = blkno; /* Queue it. */ s = splbio(); bufq_put(sc->buf_queue, bp); splx(s); if (!sc->active) mcdstart(sc); return; done: bp->b_resid = bp->b_bcount; biodone(bp); }
/* * State machine to process read requests. * Initialize with MCD_S_BEGIN: calculate sizes, and set mode * MCD_S_WAITMODE: waits for status reply from set mode, set read command * MCD_S_WAITREAD: wait for read ready, read data. */ int mcdintr(void *arg) { struct mcd_softc *sc = arg; struct mcd_mbx *mbx = &sc->mbx; struct buf *bp = mbx->bp; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; int i; u_char x; bcd_t msf[3]; switch (mbx->state) { case MCD_S_IDLE: return 0; case MCD_S_BEGIN: tryagain: if (mbx->mode == sc->lastmode) goto firstblock; sc->lastmode = MCD_MD_UNKNOWN; bus_space_write_1(iot, ioh, MCD_COMMAND, MCD_CMDSETMODE); bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->mode); mbx->count = RDELAY_WAITMODE; mbx->state = MCD_S_WAITMODE; case MCD_S_WAITMODE: callout_stop(&sc->sc_pintr_ch); for (i = 20; i; i--) { x = bus_space_read_1(iot, ioh, MCD_XFER); if ((x & MCD_XF_STATUSUNAVAIL) == 0) break; delay(50); } if (i == 0) goto hold; sc->status = bus_space_read_1(iot, ioh, MCD_STATUS); mcd_setflags(sc); if ((sc->flags & MCDF_LOADED) == 0) goto changed; MCD_TRACE("doread: got WAITMODE delay=%d\n", RDELAY_WAITMODE - mbx->count); sc->lastmode = mbx->mode; firstblock: MCD_TRACE("doread: read blkno=%d for bp=0x%p\n", (int) mbx->blkno, bp); /* Build parameter block. */ hsg2msf(mbx->blkno, msf); /* Send the read command. */ bus_space_write_1(iot, ioh, MCD_COMMAND, sc->readcmd); bus_space_write_1(iot, ioh, MCD_COMMAND, msf[0]); bus_space_write_1(iot, ioh, MCD_COMMAND, msf[1]); bus_space_write_1(iot, ioh, MCD_COMMAND, msf[2]); bus_space_write_1(iot, ioh, MCD_COMMAND, 0); bus_space_write_1(iot, ioh, MCD_COMMAND, 0); bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->nblk); mbx->count = RDELAY_WAITREAD; mbx->state = MCD_S_WAITREAD; case MCD_S_WAITREAD: callout_stop(&sc->sc_pintr_ch); nextblock: loop: for (i = 20; i; i--) { x = bus_space_read_1(iot, ioh, MCD_XFER); if ((x & MCD_XF_DATAUNAVAIL) == 0) goto gotblock; if ((x & MCD_XF_STATUSUNAVAIL) == 0) break; delay(50); } if (i == 0) goto hold; sc->status = bus_space_read_1(iot, ioh, MCD_STATUS); mcd_setflags(sc); if ((sc->flags & MCDF_LOADED) == 0) goto changed; #if 0 printf("%s: got status byte %02x during read\n", device_xname(sc->sc_dev), (u_int)sc->status); #endif goto loop; gotblock: MCD_TRACE("doread: got data delay=%d\n", RDELAY_WAITREAD - mbx->count); /* Data is ready. */ bus_space_write_1(iot, ioh, MCD_CTL2, 0x04); /* XXX */ bus_space_read_multi_1(iot, ioh, MCD_RDATA, (char *)bp->b_data + mbx->skip, mbx->sz); bus_space_write_1(iot, ioh, MCD_CTL2, 0x0c); /* XXX */ mbx->blkno += 1; mbx->skip += mbx->sz; if (--mbx->nblk > 0) goto nextblock; mbx->state = MCD_S_IDLE; /* Return buffer. */ bp->b_resid = 0; disk_unbusy(&sc->sc_dk, bp->b_bcount, (bp->b_flags & B_READ)); biodone(bp); mcdstart(sc); return 1; hold: if (mbx->count-- < 0) { printf("%s: timeout in state %d", device_xname(sc->sc_dev), mbx->state); goto readerr; } #if 0 printf("%s: sleep in state %d\n", device_xname(sc->sc_dev), mbx->state); #endif callout_reset(&sc->sc_pintr_ch, hz / 100, mcd_pseudointr, sc); return -1; } readerr: if (mbx->retry-- > 0) { printf("; retrying\n"); goto tryagain; } else printf("; giving up\n"); changed: /* Invalidate the buffer. */ bp->b_error = EIO; bp->b_resid = bp->b_bcount - mbx->skip; disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid), (bp->b_flags & B_READ)); biodone(bp); mcdstart(sc); return -1; #ifdef notyet printf("%s: unit timeout; resetting\n", device_xname(sc->sc_dev)); bus_space_write_1(iot, ioh, MCD_RESET, MCD_CMDRESET); delay(300000); (void) mcd_getstat(sc, 1); (void) mcd_getstat(sc, 1); /*sc->status &= ~MCD_ST_DSKCHNG; */ sc->debug = 1; /* preventive set debug mode */ #endif }