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 + -
显示快捷键?