GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,363 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pm_flash.h"
|
||||
#include "pm_mtd.h"
|
||||
|
||||
#define MAX_PARTS 32 /* Flash max partition number*/
|
||||
#define MAX_MTD_PARTITION (MAX_PARTS)
|
||||
|
||||
#define TMP_READ_BUF_SIZE 512
|
||||
#define MTD_INFO_DEV "/proc/mtd"
|
||||
|
||||
static xmedia_char *skip_space(xmedia_char *line)
|
||||
{
|
||||
xmedia_char *p = line;
|
||||
while (*p == ' ' || *p == '\t') {
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static xmedia_char *get_word(xmedia_char *line, xmedia_char *value)
|
||||
{
|
||||
xmedia_char *p = line;
|
||||
p = skip_space(p);
|
||||
while (*p != '\t' && *p != ' ' && *p != '\n' && *p != 0) {
|
||||
*value++ = *p++;
|
||||
}
|
||||
*value = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
static xmedia_u32 file_name_start(xmedia_char *name)
|
||||
{
|
||||
xmedia_u32 size = 0;
|
||||
|
||||
if (name) {
|
||||
size = strlen(name);
|
||||
if (size == 0)
|
||||
return size;
|
||||
|
||||
while (size--) {
|
||||
if (name[size] == '/')
|
||||
return size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static xmedia_s32 get_dname_from_pname(struct flash_part_dev *part_dev)
|
||||
{
|
||||
FILE *fd;
|
||||
xmedia_char *buff;
|
||||
xmedia_s32 ret = -1;
|
||||
xmedia_s32 i = 0;
|
||||
xmedia_char *p;
|
||||
xmedia_char devname[FLASH_NAME_LEN];
|
||||
xmedia_char tmp[32];
|
||||
|
||||
buff = (xmedia_char *)malloc(TMP_READ_BUF_SIZE);
|
||||
if (buff == XMEDIA_NULL)
|
||||
return XMEDIA_ERRCODE_NOT_ENOUGH_MEMORY;
|
||||
|
||||
fd = fopen(MTD_INFO_DEV, "r");
|
||||
if (fd) {
|
||||
if (NULL == fgets(buff, TMP_READ_BUF_SIZE, fd)) {//skip first line
|
||||
fclose(fd);
|
||||
goto ERR_END;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MTD_PARTITION; i++) {
|
||||
if (fgets(buff, TMP_READ_BUF_SIZE, fd) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
p = &buff[0];
|
||||
p = get_word(p, devname);
|
||||
p = get_word(p, tmp);
|
||||
part_dev->part.size = (xmedia_u32)strtoull(tmp, NULL, 16);
|
||||
|
||||
p = get_word(p, tmp);
|
||||
part_dev->part.block_size = (xmedia_u32)strtoull(tmp, NULL, 16);
|
||||
|
||||
p = get_word(p, tmp);
|
||||
if (strncmp(&tmp[1], part_dev->part.partname, strlen(part_dev->part.partname)) == 0){
|
||||
|
||||
/* delete ':' */
|
||||
devname[strlen(devname) - 1] = 0;
|
||||
strncpy(part_dev->part.devname + file_name_start(part_dev->part.devname), devname, FLASH_NAME_LEN);
|
||||
printf("use new devname: %s\n", part_dev->part.devname);
|
||||
ret = XMEDIA_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
ERR_END:
|
||||
free(buff);
|
||||
return ret;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* > 0 skip bad block num.
|
||||
* = 0 no bad block.
|
||||
* < 0 error.
|
||||
*/
|
||||
static xmedia_s32 check_skip_badblock(struct flash_part_dev *part_dev, xmedia_s32 *blockindex, xmedia_s32 blocksize)
|
||||
{
|
||||
xmedia_s32 rel = 0;
|
||||
xmedia_s32 badblock;
|
||||
xmedia_u64 size = part_dev->flash.part_size + 1;
|
||||
loff_t offset = ((loff_t)(*blockindex) * (loff_t)blocksize);
|
||||
|
||||
if (part_dev->part_fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
badblock = ioctl(part_dev->part_fd, MEMGETBADBLOCK, &offset);
|
||||
if (badblock < 0) {
|
||||
PM_USR_TRACE(MODULE_DBG_ERR, "Get nand badblock fail. error(%d)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (badblock == 1) {
|
||||
PM_USR_TRACE(MODULE_DBG_INFO, "Skip bad block at address: 0x%llX\n",
|
||||
(xmedia_u64)offset);
|
||||
(*blockindex)++;
|
||||
rel++;
|
||||
}
|
||||
|
||||
offset = (loff_t)(*blockindex) * (loff_t)blocksize;
|
||||
} while (badblock == 1 && offset < (loff_t)size);
|
||||
|
||||
if (offset >= (loff_t)size)
|
||||
return -1;
|
||||
|
||||
return rel;
|
||||
}
|
||||
static xmedia_s32 nand_rw(struct flash_part_dev *part_dev, xmedia_u32 addr, xmedia_u32 size, xmedia_char *buf, xmedia_s32 w)
|
||||
{
|
||||
xmedia_s32 total = 0;
|
||||
xmedia_u32 cur_offset = addr;
|
||||
xmedia_u32 remaining_len = size;
|
||||
xmedia_char *cur_buf = buf;
|
||||
xmedia_u32 page_size = part_dev->flash.page_size;
|
||||
xmedia_u32 page_mask = page_size - 1;
|
||||
xmedia_u32 block_size = part_dev->flash.block_size;
|
||||
|
||||
if ((addr & page_mask) || (size & page_mask)) {
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* check addr and size */
|
||||
if (addr > part_dev->flash.part_size || addr + size > part_dev->flash.part_size)
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
|
||||
while (remaining_len && remaining_len <= size) {
|
||||
xmedia_s32 ret = 0;
|
||||
xmedia_s32 block_index, bad_skipped;
|
||||
xmedia_u32 rw_size;
|
||||
|
||||
block_index = cur_offset / block_size;
|
||||
bad_skipped = check_skip_badblock(part_dev, &block_index, block_size);
|
||||
if (bad_skipped < 0) {
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
} else {
|
||||
cur_offset += bad_skipped * block_size;
|
||||
}
|
||||
|
||||
if (lseek(part_dev->part_fd, cur_offset, SEEK_SET) < 0) {
|
||||
PM_USR_TRACE(MODULE_DBG_ERR, "Fail to seek to 0x%x\n", addr);
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (remaining_len > block_size)
|
||||
rw_size = block_size;
|
||||
else
|
||||
rw_size = remaining_len;
|
||||
|
||||
if (w)
|
||||
ret = write(part_dev->part_fd, cur_buf, rw_size);
|
||||
else
|
||||
ret = read(part_dev->part_fd, cur_buf, rw_size);
|
||||
|
||||
if (ret < 0) {
|
||||
PM_USR_TRACE(MODULE_DBG_ERR, "Fail to %s at 0x%x\n", w ? "write" : "read", addr);
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
cur_buf += rw_size;
|
||||
cur_offset += rw_size;
|
||||
remaining_len -= rw_size;
|
||||
total += ret;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
static xmedia_s32 nand_read(struct flash_part_dev *part_dev, xmedia_u32 addr, xmedia_u32 size, xmedia_char *buf)
|
||||
{
|
||||
return nand_rw(part_dev, addr, size, buf, 0);
|
||||
}
|
||||
|
||||
static xmedia_s32 nand_write(struct flash_part_dev *part_dev, xmedia_u32 addr, xmedia_u32 size, xmedia_char *buf)
|
||||
{
|
||||
return nand_rw(part_dev, addr, size, buf, 1);
|
||||
}
|
||||
|
||||
static xmedia_s32 nand_erase(struct flash_part_dev *part_dev, xmedia_u32 addr, xmedia_u32 size)
|
||||
{
|
||||
xmedia_u32 cur_offset = addr;
|
||||
xmedia_u32 remaining_len = size;
|
||||
xmedia_u32 block_size = part_dev->flash.block_size;
|
||||
xmedia_u32 block_mask = block_size - 1;
|
||||
struct erase_info_user64 eraseinfo;
|
||||
xmedia_s32 ret;
|
||||
|
||||
if ((addr & block_mask) || (size & block_mask)) {
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* check addr and size */
|
||||
if (addr > part_dev->flash.part_size || addr + size > part_dev->flash.part_size)
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
|
||||
while (remaining_len && remaining_len <= size) {
|
||||
xmedia_s32 block_index, bad_skipped;
|
||||
|
||||
block_index = cur_offset / block_size;
|
||||
bad_skipped = check_skip_badblock(part_dev, &block_index, block_size);
|
||||
if (bad_skipped < 0) {
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
} else {
|
||||
cur_offset += bad_skipped * block_size;
|
||||
}
|
||||
|
||||
eraseinfo.start = cur_offset;
|
||||
eraseinfo.length = block_size;
|
||||
|
||||
ret = ioctl(part_dev->part_fd, MEMERASE64, &eraseinfo);
|
||||
if (ret != 0) {
|
||||
PM_USR_TRACE(MODULE_DBG_ERR, "%s erase error ret:%d\n", __func__, ret);
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
}
|
||||
|
||||
cur_offset += block_size;
|
||||
remaining_len -= block_size;
|
||||
}
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
static xmedia_s32 nand_open(struct flash_part_dev *part_dev, unsigned int flag)
|
||||
{
|
||||
if (part_dev->part.partname[0] != 0)
|
||||
get_dname_from_pname(part_dev);
|
||||
|
||||
part_dev->part_fd = open(part_dev->part.devname, flag);
|
||||
return part_dev->part_fd;
|
||||
}
|
||||
|
||||
static xmedia_s32 nand_close(struct flash_part_dev *part_dev)
|
||||
{
|
||||
close(part_dev->part_fd);
|
||||
part_dev->part_fd = -1;
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
static xmedia_s32 nand_init(struct flash_part_dev *part_dev)
|
||||
{
|
||||
struct mtd_info_user mtdinfo;
|
||||
xmedia_s32 ret;
|
||||
|
||||
ret = ioctl(part_dev->part_fd, MEMGETINFO, &mtdinfo);
|
||||
if (ret != 0) {
|
||||
PM_USR_TRACE(MODULE_DBG_ERR, "%s mem get info error ret:%d\n", __func__, ret);
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
}
|
||||
|
||||
part_dev->flash.block_size = mtdinfo.erasesize;
|
||||
part_dev->flash.page_size = mtdinfo.writesize;
|
||||
part_dev->flash.oob_size = mtdinfo.oobsize;
|
||||
part_dev->flash.part_size = mtdinfo.size;
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
static xmedia_s32 nand_getinfo(struct flash_part_dev *part_dev)
|
||||
{
|
||||
xmedia_s32 ret = -1;
|
||||
xmedia_s32 i = 0;
|
||||
xmedia_char *buff;
|
||||
FILE *fd;
|
||||
xmedia_char *p;
|
||||
xmedia_char tmp[32];
|
||||
|
||||
buff = (xmedia_char *)malloc(TMP_READ_BUF_SIZE);
|
||||
if (buff == XMEDIA_NULL)
|
||||
return XMEDIA_ERRCODE_NOT_ENOUGH_MEMORY;
|
||||
|
||||
fd = fopen(MTD_INFO_DEV, "r");
|
||||
if (fd) {
|
||||
if (NULL == fgets(buff, TMP_READ_BUF_SIZE, fd)) {//skip first line
|
||||
fclose(fd);
|
||||
goto ERR_END;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MTD_PARTITION; i++) {
|
||||
if (fgets(buff, TMP_READ_BUF_SIZE, fd) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
p = &buff[0];
|
||||
p = get_word(p, tmp);
|
||||
if (strncmp(tmp, &part_dev->part.devname[5], strlen(&part_dev->part.devname[5])) == 0) {
|
||||
p = get_word(p, tmp);
|
||||
part_dev->part.size = (xmedia_u32)strtoull(tmp, NULL, 16);
|
||||
|
||||
p = get_word(p, tmp);
|
||||
part_dev->part.block_size = (xmedia_u32)strtoull(tmp, NULL, 16);
|
||||
|
||||
p = get_word(p, tmp);
|
||||
strncpy(part_dev->part.partname, &tmp[1], (strlen(&tmp[1]) - 1) < FLASH_NAME_LEN ? (strlen(&tmp[1]) - 1) : FLASH_NAME_LEN);
|
||||
|
||||
ret = XMEDIA_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
ERR_END:
|
||||
free(buff);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct flash_opt nand_opt = {
|
||||
.read = nand_read,
|
||||
.write = nand_write,
|
||||
.erase = nand_erase,
|
||||
.init = nand_init,
|
||||
.open = nand_open,
|
||||
.close = nand_close,
|
||||
.get_info = nand_getinfo,
|
||||
};
|
||||
|
||||
struct flash_opt *get_nand_opt(void)
|
||||
{
|
||||
return &nand_opt;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user