devio.c
来自「Centrality Atlas II development software」· C语言 代码 · 共 343 行
C
343 行
/* * $QNXLicenseC: * Copyright 2007,2008, QNX Software Systems. * * Licensed under the Apache License, Version 2.0 (the "License"). You * may not reproduce, modify or distribute this software except in * compliance with the License. You may obtain a copy of the License * at: http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * * This file may contain contributions from others, either as * contributors under the License or as licensors under other terms. * Please review this entire file for other proprietary rights or license * notices, as well as the QNX Development Suite License Guide at * http://licensing.qnx.com/license-guide/ for other information. * $ */#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#include <gulliver.h>#include <sys/slog.h>#include <sys/neutrino.h>#include <fs/etfs.h>#include "devio.h"//// Initialize the part and stuff physical paramaters for the part.//int devio_init(struct etfs_devio *dev) { uint8_t id[4]; CHIPIO *cio = dev->cio; // Allow IO operations if(ThreadCtl(_NTO_TCTL_IO, 0) != EOK) { dev->log(_SLOG_CRITICAL, "You must be root."); // We will not return } // Do anything special to get the part ready to use if(nand_init(dev) != 0) { dev->log(_SLOG_CRITICAL, "nand_init failed : %s", strerror(errno)); // We will not return } // Reset the part nand_write_cmd(cio, NANDCMD_RESET); if(nand_wait_busy(cio, MAX_RESET_USEC) != 0) dev->log(_SLOG_CRITICAL, "Timeout on RESET"); if(nand_read_flashid(cio, id, 4)!=0) dev->log(_SLOG_CRITICAL, "Timeout on ReadID"); switch(id[1]) { // 16M case 0x73: dev->numblks = 1024; cio->addrcycles = 3; break; // 32M case 0x75: dev->numblks = 2048; cio->addrcycles = 3; break; // 64M case 0x76: dev->numblks = 4096; cio->addrcycles = 4; break; // 128M case 0x72: case 0x74: case 0x78: case 0x79: dev->numblks = 8192; cio->addrcycles = 4; break; default: dev->log(_SLOG_CRITICAL, "Unsupported NAND device (%2.2x %2.2x)", id[0], id[1]); // We will not return } // These must be initialized here. All other numbers are built from them. sprintf(dev->id, "NAND%2.2x%2.2x", id[0], id[1]); dev->memtype = ETFS_MEMTYPE_NAND; // We glue to physical pages at the driver and report back their combined size dev->clustersize = DATASIZE * PAGES2CLUSTER; dev->sparesize = SPARESIZE * PAGES2CLUSTER; dev->clusters2blk = PAGES2BLK / PAGES2CLUSTER; dev->blksize = (dev->clustersize + SPARESIZE) * dev->clusters2blk; cio->lastpage = ~0; return(EOK);}//// Read a cluster of data.//// Verify crc for both the spare area and the data area.// The passed buffer "buf" is larger than the cluster size. It can hold// (PAGESIZE * PAGES2CLUSTER) bytes. This is for convienence when reading// data from the device ands calculating the crc. The work area after clustersize// bytes is ignored by the caller.//// We combine 2 pages to make a single cluster. This was necessary to get enough// spare bytes to store all the needed information. It would not fit in 16 bytes.//int devio_readcluster(struct etfs_devio *dev, unsigned cluster, uint8_t *buf, struct etfs_trans *trp) { struct spare1 *sp1; struct spare2 *sp2; int err, err2; unsigned page = cluster * PAGES2CLUSTER; volatile unsigned crcdata; CHIPIO *cio = dev->cio; uint8_t erasesig=0; nand_read_page(cio, page, buf, PAGESIZE, 0); if(nand_wait_busy(cio, MAX_READ_USEC) != 0) dev->log(_SLOG_CRITICAL, "Timeout on READ"); sp1 = (struct spare1 *)(buf + DATASIZE); if(sp1->status != 0xff) { dev->log(_SLOG_ERROR, "readcluster BADBLK on cluster %d", cluster); trp->tacode = ETFS_TRANS_BADBLK; } else if(((uint64_t *)sp1)[0] == ~0ll && ((uint32_t *)sp1)[2] == ~0 && sp1->nclusters == 0xff && sp1->crctrans == 0xffff) { if(sp1->erasesig == ERASESIG) trp->tacode = ETFS_TRANS_ERASED; else trp->tacode = ETFS_TRANS_FOXES; } else if(dev->crc16((uint8_t *) sp1, sizeof(*sp1) - sizeof(sp1->crctrans)) != sp1->crctrans) { dev->log(_SLOG_ERROR, "readcluster trans DATAERR on cluster %d", cluster); trp->tacode = ETFS_TRANS_DATAERR; } else trp->tacode = ETFS_TRANS_OK; crcdata = (uint16_t)sp1->crcdatalo; erasesig=sp1->erasesig; // Build transaction data from data in the spare area. trp->sequence = ENDIAN_LE32(sp1->sequence); trp->fid = ENDIAN_LE16(sp1->fid); trp->cluster = ENDIAN_LE16(sp1->clusterlo) + (sp1->clusterhi << 16); trp->nclusters = sp1->nclusters; // // Second page read from device // nand_read_page(cio, page+1, buf + DATASIZE, PAGESIZE, 0); if(nand_wait_busy(cio, MAX_READ_USEC) != 0) dev->log(_SLOG_CRITICAL, "Timeout on READ"); cio->lastpage = page + 1; sp2 = (struct spare2 *) (buf + 2*DATASIZE); crcdata |= sp2->crcdatahi << 16; trp->dacode = ETFS_TRANS_OK; if(trp->tacode == ETFS_TRANS_OK) { if(dev->crc32(buf, 2*DATASIZE) != crcdata) { err = dev->ecc(buf, &sp2->ecc1[0], 1, 1); err2 = dev->ecc(buf + 256, &sp2->ecc234[0], 3, 1); if(err >= ETFS_ECC_ERROR || err2 >= ETFS_ECC_ERROR || dev->crc32(buf, 2*DATASIZE) != crcdata) { dev->log(_SLOG_ERROR, "readcluster DATAERR on cluster %d", cluster); return(trp->dacode = ETFS_TRANS_DATAERR); } dev->log(_SLOG_ERROR, "readcluster ECCERR on cluster %d", cluster); return(trp->dacode = ETFS_TRANS_ECC); } } return(trp->tacode);}//// Read the spare area of a page (not the data) to return transaction infoormation.//// This called is used heavily on startup to process the transactions. It is// a cheaper call than readcluster() since it reads less data and has a smaller// checksum to calculate.//int devio_readtrans(struct etfs_devio *dev, unsigned cluster, struct etfs_trans *trp) { struct spare1 spare1; unsigned page = cluster * PAGES2CLUSTER; CHIPIO *cio = dev->cio; nand_read_page(cio, page, (uint8_t *)&spare1, sizeof(spare1), 1); if(nand_wait_busy(cio, MAX_READ_USEC) != 0) dev->log(_SLOG_CRITICAL, "Timeout on READ"); cio->lastpage = page; if(spare1.status != 0xff) { dev->log(_SLOG_ERROR, "readtrans BADBLK on cluster %d", cluster); return(ETFS_TRANS_BADBLK); } if(((uint64_t *)&spare1)[0] == ~0ll && ((uint32_t *)&spare1)[2] == ~0 && spare1.nclusters == 0xff && spare1.crctrans == 0xffff) if(spare1.erasesig == ERASESIG) return(ETFS_TRANS_ERASED); else return(ETFS_TRANS_FOXES); if(dev->crc16((uint8_t *) &spare1, sizeof(spare1) - sizeof(spare1.crctrans)) != spare1.crctrans) { dev->log(_SLOG_ERROR, "readtrans DATAERR on cluster %d", cluster); return(ETFS_TRANS_DATAERR); } trp->sequence = ENDIAN_LE32(spare1.sequence); trp->fid = ENDIAN_LE16(spare1.fid); trp->cluster = ENDIAN_LE16(spare1.clusterlo) + (spare1.clusterhi << 16); trp->nclusters = spare1.nclusters; return(ETFS_TRANS_OK);}//// Post a cluster of data.//// Set crc for both the spare area and the data area.// The passed buffer "buf" is larger than the cluster size. It can hold// (PAGESIZE * PAGES2CLUSTER) bytes. This is for convienence writing// data to the device ands calculating the crc. The work area after clustersize// bytes is ignored by the caller.//int devio_postcluster(struct etfs_devio *dev, unsigned cluster, uint8_t *buf, struct etfs_trans *trp) { struct spare1 *sp1; struct spare2 *sp2; //int ret; uint32_t status; unsigned page = cluster * PAGES2CLUSTER; volatile unsigned crcdata; CHIPIO *cio = dev->cio; // Build second spare area sp2 = (struct spare2 *) (buf + 2*DATASIZE); memset((void *)sp2, 0xff, sizeof(*sp2)); dev->ecc(buf, &sp2->ecc1[0], 1, 0); dev->ecc(buf + 256, &sp2->ecc234[0], 3, 0); // Build first spare area sp1 = (struct spare1 *) (buf + 2*DATASIZE + SPARESIZE); memset((void *)sp1, 0xff, sizeof(*sp1)); if(trp) { sp1->erasesig = 0; sp1->sequence = ENDIAN_LE32(trp->sequence); sp1->fid = ENDIAN_LE16((uint16_t) trp->fid); sp1->clusterlo = ENDIAN_LE16((uint16_t) trp->cluster); sp1->clusterhi = (uint8_t)(trp->cluster >> 16); sp1->nclusters =(uint8_t) trp->nclusters; crcdata = dev->crc32(buf, 2*DATASIZE); sp1->crcdatalo =(uint16_t) crcdata; sp2->crcdatahi = (uint16_t)(crcdata >> 16); sp1->crctrans = (uint16_t)dev->crc16((uint8_t *) sp1, sizeof(*sp1) - sizeof(sp1->crctrans)); } else sp1->erasesig = ERASESIG; if(nand_write_page(cio, page, buf, DATASIZE, 0)!=0) dev->log(_SLOG_CRITICAL, "Timeout on POST DATA"); if(nand_write_page(cio, page, (uint8_t *)sp1, SPARESIZE, 1)!=0) dev->log(_SLOG_CRITICAL, "Timeout on POST SPARE"); if(nand_read_status(cio, (uint8_t *)&status) !=0) dev->log(_SLOG_ERROR, "Timeout on ReadStatus --write page spare"); if(((status & 0xFF) & 0x01) != 0) { dev->log(_SLOG_ERROR, "Post SPARE error on page %d (0x%x)", page, status); return(ETFS_TRANS_DEVERR); } // Our work is done if called from devio_eraseblk() if(trp == NULL) return(ETFS_TRANS_OK); // Write second page of data ++page; if(nand_write_page(cio, page, buf + DATASIZE, DATASIZE, 0)!=0) dev->log(_SLOG_CRITICAL, "Timeout on POST DATA"); if(nand_write_page(cio, page, (buf + 2*DATASIZE), SPARESIZE, 1)!=0) dev->log(_SLOG_CRITICAL, "Timeout on POST SPARE"); if(nand_read_status(cio, (uint8_t *)&status) !=0) dev->log(_SLOG_ERROR, "Timeout on ReadStatus"); if(((status & 0xFF) & 0x01) != 0) { dev->log(_SLOG_ERROR, "Post SPARE error on second page %d (0x%x)", page, status); return(ETFS_TRANS_DEVERR); } return(ETFS_TRANS_OK);}// Erase a block.int devio_eraseblk(struct etfs_devio *dev, unsigned blk) { uint32_t status=0; CHIPIO *cio = dev->cio; uint8_t *buf = alloca(PAGESIZE * PAGES2CLUSTER); if(nand_erase_blk(cio, blk)!=0) dev->log(_SLOG_CRITICAL, "Timeout on ERASE"); if(nand_read_status(cio, (uint8_t *)&status) !=0) dev->log(_SLOG_ERROR, "Timeout on ReadStatus after Erase"); if((status & 0xC1) != 0xC0) { dev->log(_SLOG_ERROR, "erase error on blk %d (0x%x)", blk, status); return(ETFS_TRANS_DEVERR); } // Write the erase signature. We only write non FFs in the first 16 bytes of the // spare area and put FFs everywhere else. memset(buf, 0xff, PAGESIZE * PAGES2CLUSTER); status = devio_postcluster(dev, blk * dev->clusters2blk, buf, NULL); return(status);}//// Called to allow the driver to flush any cached data that// has not be written to the device. The NAND class driver does// not need it.//int devio_sync(struct etfs_devio *dev) { return(-1);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?