/**************************************************************************** * apps/examples/flash_test/flash_test.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file 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 OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** * Private data ****************************************************************************/ /**************************************************************************** * Public Functions ****************************************************************************/ int main(int argc, FAR char *argv[]) { struct inode *inode; int ret; int x; int logsector; uint16_t seq; struct smart_format_s fmt; uint16_t *sectors; uint16_t *seqs; char *buffer; struct smart_read_write_s readwrite; /* Argument given? */ if (argc < 2) { fprintf(stderr, "usage: flash_test flash_block_device\n"); return -1; } /* Find the inode of the block driver identified by 'source' */ ret = open_blockdriver(argv[1], 0, &inode); if (ret < 0) { fprintf(stderr, "Failed to open %s\n", argv[1]); return ret; } /* Get the low-level format from the device. */ ret = inode->u.i_bops->ioctl(inode, BIOC_GETFORMAT, (unsigned long) &fmt); if (ret != OK) { fprintf(stderr, "Device is not a SMART block device\n"); goto errout_with_driver; } /* Test if the device is formatted. If not, then we must do a * low-level format first */ if (!(fmt.flags & SMART_FMT_ISFORMATTED)) { /* Perform a low-level format */ inode->u.i_bops->ioctl(inode, BIOC_LLFORMAT, 0); inode->u.i_bops->ioctl(inode, BIOC_GETFORMAT, (unsigned long) &fmt); } if (!(fmt.flags & SMART_FMT_ISFORMATTED)) { fprintf(stderr, "Unable to get device format\n"); goto errout_with_driver; } /* Report the device structure */ printf("FLASH Test on device with:\n"); printf(" Sector size: %10d\n", fmt.sectorsize); printf(" Sector count: %10d\n", fmt.nsectors); printf(" Avail bytes: %10d\n", fmt.availbytes); printf(" Total size: %10d\n", fmt.sectorsize * fmt.nsectors); /* Allocate buffers to use */ buffer = (char *)malloc(fmt.availbytes); if (buffer == NULL) { fprintf(stderr, "Error allocating buffer\n"); goto errout_with_driver; } seqs = (uint16_t *)malloc(fmt.nsectors << 1); if (seqs == NULL) { free(buffer); fprintf(stderr, "Error allocating seqs buffer\n"); goto errout_with_driver; } sectors = (uint16_t *)malloc(fmt.nsectors << 1); if (sectors == NULL) { free(seqs); free(buffer); fprintf(stderr, "Error allocating sectors buffer\n"); goto errout_with_driver; } /* Write a bunch of data to the flash */ printf("\nAllocating and writing to logical sectors\n"); seq = 0; for (x = 0; x < fmt.nsectors >> 1; x++) { /* Allocate a new sector */ logsector = inode->u.i_bops->ioctl(inode, BIOC_ALLOCSECT, (unsigned long) -1); if (logsector < 0) { fprintf(stderr, "Error allocating sector: %d\n", logsector); goto errout_with_driver; } /* Save the sector in our array */ sectors[x] = (uint16_t)logsector; seqs[x] = seq++; /* Now write some data to the sector */ snprintf(buffer, fmt.availbytes, "Logical sector %d sequence %d\n", sectors[x], seqs[x]); readwrite.logsector = sectors[x]; readwrite.offset = 0; readwrite.count = strlen(buffer) + 1; readwrite.buffer = (uint8_t *)buffer; inode->u.i_bops->ioctl(inode, BIOC_WRITESECT, (unsigned long) &readwrite); /* Print the logical sector number */ printf("\r%d ", sectors[x]); } /* Now read the data back to validate everything was written and can * be read. */ printf("\nDoing read verify test\n"); for (x = 0; x < fmt.nsectors >> 1; x++) { /* Read from the logical sector */ readwrite.logsector = sectors[x]; readwrite.offset = 0; readwrite.count = fmt.availbytes; readwrite.buffer = (uint8_t *)buffer; ret = inode->u.i_bops->ioctl(inode, BIOC_READSECT, (unsigned long) &readwrite); if (ret != fmt.availbytes) { fprintf(stderr, "Error reading sector %d\n", sectors[x]); goto errout_with_buffers; } /* Generate compare string and do the compare */ printf("\r%d ", sectors[x]); snprintf(&buffer[100], fmt.availbytes - 100, "Logical sector %d sequence %d\n", sectors[x], seqs[x]); if (strcmp(buffer, &buffer[100]) != 0) { printf("Sector %d read verify failed\n", sectors[x]); } } printf("\nPeforming sector re-write\n"); /* Overwrite data on the sectors to cause relocation */ for (x = 0; x < fmt.nsectors >> 1; x++) { /* Save a new sequence number for the sector */ seqs[x] = seq++; /* Now write over the sector data with new data, causing a relocation. */ snprintf(buffer, fmt.availbytes, "Logical sector %d sequence %d\n", sectors[x], seqs[x]); readwrite.logsector = sectors[x]; readwrite.offset = 0; readwrite.count = strlen(buffer) + 1; readwrite.buffer = (uint8_t *)buffer; inode->u.i_bops->ioctl(inode, BIOC_WRITESECT, (unsigned long) &readwrite); /* Print the logical sector number */ printf("\r%d ", sectors[x]); } /* Now append data to empty region of sector */ printf("\nAppending data to empty region of sector\n"); for (x = 0; x < fmt.nsectors >> 1; x++) { /* Save a new sequence number for the sector */ seqs[x] = seq++; /* Now write over the sector data with new data, * causing a relocation. */ snprintf(buffer, fmt.availbytes, "Appended data in sector %d\n", sectors[x]); readwrite.logsector = sectors[x]; readwrite.offset = 64; readwrite.count = strlen(buffer) + 1; readwrite.buffer = (uint8_t *)buffer; inode->u.i_bops->ioctl(inode, BIOC_WRITESECT, (unsigned long) &readwrite); /* Print the logical sector number */ printf("\r%d ", sectors[x]); } printf("\nDone\n"); /* Free all the allocated sectors */ for (x = 0; x < fmt.nsectors >> 1; x++) { /* Only free the sector if it is still valid */ if (sectors[x] != 0xffff) { inode->u.i_bops->ioctl(inode, BIOC_FREESECT, (unsigned long) sectors[x]); } } errout_with_buffers: /* Free the allocated buffers */ free(seqs); free(sectors); free(buffer); errout_with_driver: /* Now close the block device and exit */ close_blockdriver(inode); return 0; }