/** * Test page write on linux (thomasbechtold@jpberlin.de) * * Compile with: gcc -o mmc-test mmc-write.c * * Usage: ./mmc-test write //write to the given device some pages * Usage: ./mmc-test read //read the pages from the device * * * show the written pages with hexdump: for X in {0..800}; do hexdump -C /dev/sdb -n 5 -s "$X"b; done */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #define PAGE_SIZE 512 #define MESSAGE_LENGTH 100 /* CHANGE THIS TO YOUR MMC DEVICE PATH */ #define MEMORY_DEVICE_PATH "/dev/sdb" /* print the given message to stdout but if the same message was already printed, just print a '*' */ void myprint (char *message) { static char message_cache[MESSAGE_LENGTH]; if (memcmp (message, &message_cache, MESSAGE_LENGTH) == 0) { // same message again printf ("*"); } else { // new message printf ("\n%s ", message); memcpy (&message_cache, message , MESSAGE_LENGTH); } } void write_page (unsigned long id) { //the page we want to write char page[PAGE_SIZE] = { 0 }; page[0] = 'P'; memcpy (&page[1], &id, sizeof (unsigned long)); //file descriptor to write and read the page int memory_fd = -1; //loop as long as the page-write (and read) was unsucessful while (1) { //buffer for a console message char message[100] = { 0 }; close (memory_fd); memory_fd = -1; errno = 0; memory_fd = open (MEMORY_DEVICE_PATH, O_RDWR, O_SYNC | O_DIRECT); if (memory_fd >= 0) { //seek to correct position (to write the page) off_t lseek_write_res = -1; errno = 0; lseek_write_res = lseek (memory_fd, id * PAGE_SIZE, SEEK_SET); if (lseek_write_res == -1 || lseek_write_res != id * PAGE_SIZE) { sprintf (message, "%lu: seek failed: %s\n", id, strerror (errno)); myprint (message); continue; } //write page errno = 0; ssize_t write_res = 0; write_res = write (memory_fd, &page, PAGE_SIZE); if (write_res == -1 || write_res != PAGE_SIZE) { sprintf (message, "%lu: write failed: %s\n", id, strerror (errno)); myprint (message); continue; } //close and reopen the device to read and check the page close (memory_fd); memory_fd = open (MEMORY_DEVICE_PATH, O_RDONLY); //seek to correct position (to read the written page) errno = 0; off_t lseek_read_res = -1; lseek_read_res = lseek (memory_fd, id * PAGE_SIZE, SEEK_SET); if (lseek_read_res == -1 || lseek_read_res != id * PAGE_SIZE) { sprintf (message, "%lu: seek failed: %s\n", id, strerror (errno)); myprint (message); continue; } //read the written page char page_read[PAGE_SIZE] = { 0 }; errno = 0; ssize_t read_res = 0; read_res = read (memory_fd, &page_read, PAGE_SIZE); if (read_res == -1 || read_res != PAGE_SIZE) { sprintf (message, "%lu: read failed: %s\n", id, strerror (errno)); myprint (message); continue; } //compare the written page with the read page if (memcmp (&page, &page_read, sizeof (PAGE_SIZE)) != 0) { sprintf (message, "%lu: compare failed.\n", id); myprint (message); continue; } //wrote successfully the page break; } else { sprintf (message, "%lu: open failed: %s\n", id, strerror (errno)); myprint (message); } } close (memory_fd); printf ("\n%lu: sucessfully written", id); } void read_page (unsigned long id) { char page[PAGE_SIZE] = { 0 }; page[0] = 'P'; memcpy (&page[1], &id, sizeof (unsigned long)); int memory_fd = -1; // open device while (1) { errno = 0; close (memory_fd); memory_fd = -1; //memory_fd = open (MEMORY_DEVICE_PATH, O_DIRECT | O_SYNC, O_RDWR); memory_fd = open (MEMORY_DEVICE_PATH, O_RDWR); if (memory_fd >= 0) { //seek to correct position (to read the written page) errno = 0; off_t lseek_read_res = -1; lseek_read_res = lseek (memory_fd, id * PAGE_SIZE, SEEK_SET); if (lseek_read_res == -1 || lseek_read_res != id * PAGE_SIZE) { printf ("%lu: seek failed: %s\n", id, strerror (errno)); continue; } //read the written page char page_read[PAGE_SIZE] = { 0 }; errno = 0; ssize_t read_res = 0; read_res = read (memory_fd, &page_read, PAGE_SIZE); if (read_res == -1 || read_res != PAGE_SIZE) { printf ("%lu: read failed: %s\n", id, strerror (errno)); continue; } //compare page if (memcmp (&page, &page_read, sizeof (PAGE_SIZE)) != 0) { printf ("%lu: compare failed.\n", id); close (memory_fd); exit (-1); } //read successfully the page break; } else { printf ("%lu: open failed: %s\n", id, strerror (errno)); } } close (memory_fd); } int main (int argc, char *argv[]) { if (argc != 2) { printf ("please tell mode: 'read' or 'write'\n"); exit (-1); } //function to use for the loop void (*mode)(unsigned long) = NULL; if (strcmp (argv[1], "read") == 0) { mode = &read_page; } else if (strcmp (argv[1], "write") == 0) { mode = &write_page; } else { printf ("unknown mode '%s'\n", argv[1]); exit (-1); } unsigned long x; for (x = 0; ; x++ ) { mode (x); } printf ("\n"); exit(EXIT_SUCCESS); }