⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devio.c

📁 QNX ADS BSP code for i.MX27 chips
💻 C
字号:
/* * $QNXLicenseC:  * Copyright 2007, 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[2];	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);	// Read id info from the part	nand_write_cmd(cio, NANDCMD_IDREAD);	nand_write_pageaddr(cio, 0, 1);	nand_read_data(cio, id, 2);		switch (id[1]) {	// 32M	case 0x35:		dev->numblks = 2048;		cio->addrcycles = 3;		break;	// 64M	case 0x36:		dev->numblks = 4096;		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, spare;	struct spare2	*sp2;	uint16_t		status;	unsigned		page = cluster * PAGES2CLUSTER;	CHIPIO			*cio = dev->cio;	/*	 * Read first page from the device	 */	nand_write_cmd(cio, NANDCMD_READ);	cio->inspare = 0;	nand_write_pageaddr(cio, page, cio->addrcycles);	if (nand_wait_busy(cio,  MAX_READ_USEC) != 0)		dev->log(_SLOG_CRITICAL, "Timeout on READ");	nand_read_data(cio, buf, PAGESIZE);	status = nand_read_status(cio);	trp->tacode = ETFS_TRANS_OK;	trp->dacode = ETFS_TRANS_OK;	sp1 = (struct spare1 *)(buf + DATASIZE);	if (sp1->status != 0xFF) {		dev->log(_SLOG_ERROR, "readculster trans BADBLK on cluster %d", cluster);		return (trp->tacode = ETFS_TRANS_BADBLK);	}	else if (sp1->unused1 == ~0 && sp1->cluster == ~0 && sp1->nclusters == 0xFF) {		if (sp1->erasesig == ERASESIG)			trp->tacode = ETFS_TRANS_ERASED;		else			trp->tacode = ETFS_TRANS_FOXES;		return (trp->tacode);	}	else {#if 0		if ((status & 0x03) > 1) {		/* Spare area ECC error */			dev->log(_SLOG_ERROR, "readcluster trans DATAERR on cluster %d", cluster);			trp->tacode = ETFS_TRANS_DATAERR;		}#endif		if ((status & 0x0C) > 0x04) {	/* Main area ECC error */			dev->log(_SLOG_ERROR, "readcluster DATAERR on cluster %d", cluster);			trp->dacode = ETFS_TRANS_DATAERR;		}	}	// Build transaction data from data in the spare area 1.	trp->nclusters = sp1->nclusters;	trp->cluster   = sp1->cluster;	memcpy(&spare, sp1, sizeof(spare));	/*	 * Read second page from device	 */	nand_write_cmd(cio, NANDCMD_READ);	nand_write_pageaddr(cio, ++page, cio->addrcycles);	if (nand_wait_busy(cio,  MAX_READ_USEC) != 0)		dev->log(_SLOG_CRITICAL, "Timeout on READ");	nand_read_data(cio, buf + DATASIZE, PAGESIZE);	status = nand_read_status(cio);	cio->lastpage = page;	sp2 = (struct spare2 *) (buf + 2 * DATASIZE);	if (sp2->status != 0xFF) {		dev->log(_SLOG_ERROR, "readculster trans BADBLK on cluster %d", cluster);		return (trp->tacode = ETFS_TRANS_BADBLK);	}	// Build transaction data from data in the spare area 2.	trp->sequence = ENDIAN_LE32(sp2->sequence);	trp->fid      = ENDIAN_LE16(sp2->fid);	if (trp->tacode == ETFS_TRANS_OK){		if ((status & 0x0C) > 0x04) {	/* Main area ECC error */			dev->log(_SLOG_ERROR, "readcluster DATAERR on cluster %d", cluster);			return (trp->dacode = ETFS_TRANS_DATAERR);		}		else if ((status & 0x03) > 1) {		/* Spare area ECC error */			dev->log(_SLOG_ERROR, "readcluster ECCERR on cluster %d", cluster);			return (trp->tacode = ETFS_TRANS_DATAERR);		}		memcpy(sp2->ecc, &spare.nclusters, 5);		if (dev->crc16((uint8_t *)sp2, sizeof(*sp2) - sizeof(sp2->crctrans)) != sp2->crctrans) {			dev->log(_SLOG_ERROR, "readtrans DATAERR on cluster %d", cluster);			return (trp->tacode = ETFS_TRANS_DATAERR);		}	}	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;	struct spare2	spare2;	unsigned		page = cluster * PAGES2CLUSTER;	CHIPIO			*cio = dev->cio;	uint16_t		status;	nand_write_cmd(cio, NANDCMD_SPAREREAD);	cio->inspare = 1;	nand_write_pageaddr(cio, page, cio->addrcycles);	if (nand_wait_busy(cio, MAX_READ_USEC) != 0)		dev->log(_SLOG_CRITICAL, "Timeout on READ");	nand_read_data(cio, (uint8_t *)&spare1, sizeof(spare1));	status = nand_read_status(cio);	cio->lastpage = page;	if (spare1.status != 0xFF) {		dev->log(_SLOG_ERROR, "readtrans BADBLK on cluster %d", cluster);		return (ETFS_TRANS_BADBLK);	}	if (spare1.unused1 == ~0 && spare1.cluster == ~0 && spare1.nclusters == 0xFF) {		if (spare1.erasesig == ERASESIG)			return (ETFS_TRANS_ERASED);		else 			return (ETFS_TRANS_FOXES);	}#if 0	if ((status & 0x03) > 1) {		dev->log(_SLOG_ERROR, "readtrans DATAERR on cluster %d", cluster);		return (ETFS_TRANS_DATAERR);	}#endif	trp->nclusters = spare1.nclusters;	trp->cluster   = spare1.cluster;	/*	 * Second page read from device	 */	nand_write_cmd(cio, NANDCMD_SPAREREAD);	nand_write_pageaddr(cio, ++page, cio->addrcycles);	if (nand_wait_busy(cio,  MAX_READ_USEC) != 0)		dev->log(_SLOG_CRITICAL, "Timeout on READ");	nand_read_data(cio, (uint8_t *)&spare2, sizeof(spare2));	cio->lastpage = page;	if (spare2.status != 0xFF) {		dev->log(_SLOG_ERROR, "readtrans BADBLK on cluster %d", cluster);		return (ETFS_TRANS_BADBLK);	}	status = nand_read_status(cio);	if ((status & 0x03) > 1) {	/* Spare area ECC error */		dev->log(_SLOG_ERROR, "readtrans DATAERR (ECC) on cluster %d", cluster);		return (ETFS_TRANS_DATAERR);	}	/*	 * Check CRC for trans aera	 */	memcpy(spare2.ecc, &spare1.nclusters, 5);	if (dev->crc16((uint8_t *)&spare2, sizeof(spare2) - sizeof(spare2.crctrans)) != spare2.crctrans) {		dev->log(_SLOG_ERROR, "readtrans DATAERR on cluster %d", cluster);		return (ETFS_TRANS_DATAERR);	}	trp->sequence  = ENDIAN_LE32(spare2.sequence);	trp->fid       = ENDIAN_LE16(spare2.fid);	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;	uint8_t			status;	unsigned		page = cluster * PAGES2CLUSTER;	CHIPIO			*cio = dev->cio;	// Build second spare area	sp2 = (struct spare2 *) (buf + 2 * DATASIZE);	memset((void *)sp2, 0xff, sizeof(*sp2));	// Build spare areas	sp1 = (struct spare1 *) (buf + 2 * DATASIZE + SPARESIZE);	memset((void *)sp1, 0xff, sizeof(*sp1));	if (trp) {		sp1->erasesig       = 0;		sp1->nclusters      = trp->nclusters;		sp1->cluster        = trp->cluster;		sp2->sequence       = ENDIAN_LE32(trp->sequence);		sp2->fid            = ENDIAN_LE16((uint16_t) trp->fid);		memcpy(sp2->ecc, &sp1->nclusters, 5);		sp2->crctrans       = dev->crc16((uint8_t *)sp2, sizeof(*sp2) - sizeof(sp2->crctrans));	}	else		sp1->erasesig = ERASESIG;	// Write first page of data	// This forces us out of the spare area.	if (cio->inspare) {		nand_write_cmd(cio, NANDCMD_READ);		cio->inspare = 0;	}	nand_write_cmd(cio, NANDCMD_PROGRAM);	nand_write_pageaddr(cio, page, cio->addrcycles);	nand_write_data(cio, buf, (uint8_t *)sp1);	nand_write_cmd(cio, NANDCMD_PROGRAMCONFIRM);	if (nand_wait_busy(cio, MAX_POST_USEC) != 0)		dev->log(_SLOG_CRITICAL, "Timeout on POST");	nand_write_cmd(cio, NANDCMD_STATUSREAD);	nand_read_data(cio, &status, 1);	if ((status & 0x01) != 0) {		dev->log(_SLOG_ERROR, "Post error on page %d", page);		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	nand_write_cmd(cio, NANDCMD_PROGRAM);	nand_write_pageaddr(cio, ++page, cio->addrcycles);	nand_write_data(cio, buf + DATASIZE, (uint8_t *)sp2);	nand_write_cmd(cio, NANDCMD_PROGRAMCONFIRM);	if (nand_wait_busy(cio, MAX_POST_USEC) != 0)		dev->log(_SLOG_CRITICAL, "Timeout on POST");	nand_write_cmd(cio, NANDCMD_STATUSREAD);	nand_read_data(cio, &status, 1);	if ((status & 0x01) != 0) {		dev->log(_SLOG_ERROR, "Post error on page %d", page);		return (ETFS_TRANS_DEVERR);	}	return (ETFS_TRANS_OK);}//// Erase a block.//int devio_eraseblk(struct etfs_devio *dev, unsigned blk) {	uint8_t			status;	CHIPIO			*cio = dev->cio;	uint8_t			*buf = alloca(PAGESIZE * PAGES2CLUSTER);	nand_write_cmd(cio, NANDCMD_ERASE);	nand_write_blkaddr(cio, blk, cio->addrcycles - 1);	nand_write_cmd(cio, NANDCMD_ERASECONFIRM);	if (nand_wait_busy(cio, MAX_ERASE_USEC) != 0)		dev->log(_SLOG_CRITICAL, "Timeout on ERASE");	nand_write_cmd(cio, NANDCMD_STATUSREAD);	nand_read_data(cio, &status, 1);	if ((status & 0xC1) != 0xC0) {		dev->log(_SLOG_ERROR, "erase error on blk %d (%2.2x)", 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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -