Index: sd_raw.c
===================================================================
--- sd_raw.c	(.../sd-reader_release_20060816)	(Revision 106)
+++ sd_raw.c	(.../sd-reader_release_20060824)	(Revision 106)
@@ -4,14 +4,10 @@
  * published by the Free Software Foundation.
  */
 
+#include <string.h>
 #include <avr/io.h>
-
 #include "sd_raw.h"
 
-#if !SD_RAW_SAVE_RAM
-#include <string.h>
-#endif
-
 /**
  * \addtogroup sd_raw MMC/SD card raw access
  *
@@ -728,3 +724,129 @@
 #endif
 }
 
+/**
+ * \ingroup sd_raw
+ * Reads informational data from the card.
+ *
+ * This function reads and returns the card's registers
+ * containing manufacturing and status information.
+ *
+ * \note: The information retrieved by this function is
+ *        not required in any way to operate on the card,
+ *        but it might be nice to display some of the data
+ *        to the user.
+ *
+ * \param[in] info A pointer to the structure into which to save the information.
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t sd_raw_get_info(struct sd_raw_info* info)
+{
+    if(!info || !sd_raw_available())
+        return 0;
+
+    memset(info, 0, sizeof(*info));
+
+    select_card();
+
+    /* read cid register */
+    if(sd_raw_send_command_r1(CMD_SEND_CID, 0))
+    {
+        unselect_card();
+        return 0;
+    }
+    while(sd_raw_rec_byte() != 0xfe);
+    for(uint8_t i = 0; i < 18; ++i)
+    {
+        uint8_t b = sd_raw_rec_byte();
+
+        switch(i)
+        {
+            case 0:
+                info->manufacturer = b;
+                break;
+            case 1:
+            case 2:
+                info->oem[i - 1] = b;
+                break;
+            case 3:
+            case 4:
+            case 5:
+            case 6:
+            case 7:
+                info->product[i - 3] = b;
+                break;
+            case 8:
+                info->revision = b;
+                break;
+            case 9:
+            case 10:
+            case 11:
+            case 12:
+                info->serial |= (uint32_t) b << ((12 - i) * 8);
+                break;
+            case 13:
+                info->manufacturing_year = b << 4;
+                break;
+            case 14:
+                info->manufacturing_year |= b >> 4;
+                info->manufacturing_month = b & 0x0f;
+                break;
+        }
+    }
+
+    /* read csd register */
+    uint8_t csd_read_bl_len = 0;
+    uint8_t csd_c_size_mult = 0;
+    uint16_t csd_c_size = 0;
+    if(sd_raw_send_command_r1(CMD_SEND_CSD, 0))
+    {
+        unselect_card();
+        return 0;
+    }
+    while(sd_raw_rec_byte() != 0xfe);
+    for(uint8_t i = 0; i < 18; ++i)
+    {
+        uint8_t b = sd_raw_rec_byte();
+
+        switch(i)
+        {
+            case 5:
+                csd_read_bl_len = b & 0x0f;
+                break;
+            case 6:
+                csd_c_size = (uint16_t) (b & 0x03) << 8;
+                break;
+            case 7:
+                csd_c_size |= b;
+                csd_c_size <<= 2;
+                break;
+            case 8:
+                csd_c_size |= b >> 6;
+                ++csd_c_size;
+                break;
+            case 9:
+                csd_c_size_mult = (b & 0x03) << 1;
+                break;
+            case 10:
+                csd_c_size_mult |= b >> 7;
+
+                info->capacity = (uint32_t) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2);
+
+                break;
+            case 14:
+                if(b & 0x40)
+                    info->flag_copy = 1;
+                if(b & 0x20)
+                    info->flag_write_protect = 1;
+                if(b & 0x10)
+                    info->flag_write_protect_temp = 1;
+                info->format = (b & 0x0c) >> 2;
+                break;
+        }
+    }
+
+    unselect_card();
+
+    return 1;
+}
+
Index: fat16.c
===================================================================
--- fat16.c	(.../sd-reader_release_20060816)	(Revision 106)
+++ fat16.c	(.../sd-reader_release_20060824)	(Revision 106)
@@ -10,7 +10,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <avr/pgmspace.h>
 
 /**
  * \addtogroup fat16 FAT16 support
@@ -243,36 +242,19 @@
  */
 uint8_t fat16_read_header(struct fat16_fs_struct* fs)
 {
-    uint8_t buffer[25];
-    struct partition_struct* partition;
-    struct fat16_header_struct* header;
-    
-    if(!fs || !fs->partition)
+    if(!fs)
         return 0;
 
-    partition = fs->partition;
-    header = &fs->header;
-    
-    uint32_t partition_offset = partition->offset * 512;
-
-    /* ensure we really have a FAT16 fs here */
-    memset(buffer, 0, sizeof(buffer));
-
-    if(!partition->device_read(partition_offset + 0x36, buffer, 8) ||
-       !partition->device_read(partition_offset + 0x52, buffer + 9, 8))
+    struct partition_struct* partition = fs->partition;
+    if(!partition)
         return 0;
-    if(strcmp_P((char*) buffer, PSTR("FAT16   ")) &&
-       strcmp_P((char*) buffer + 9, PSTR("FAT16   ")))
-        return 0;
 
-    partition->type = PARTITION_TYPE_FAT16;
-
     /* read fat parameters */
+    uint8_t buffer[25];
+    uint32_t partition_offset = partition->offset * 512;
     if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer)))
         return 0;
 
-    memset(header, 0, sizeof(*header));
-    
     uint16_t bytes_per_sector = ((uint16_t) buffer[0x00]) |
                                 ((uint16_t) buffer[0x01] << 8);
     uint8_t sectors_per_cluster = buffer[0x02];
@@ -281,6 +263,8 @@
     uint8_t fat_copies = buffer[0x05];
     uint16_t max_root_entries = ((uint16_t) buffer[0x06]) |
                                 ((uint16_t) buffer[0x07] << 8);
+    uint16_t sector_count_16 = ((uint16_t) buffer[0x08]) |
+                               ((uint16_t) buffer[0x09] << 8);
     uint16_t sectors_per_fat = ((uint16_t) buffer[0x0b]) |
                                ((uint16_t) buffer[0x0c] << 8);
     uint32_t sector_count = ((uint32_t) buffer[0x15]) |
@@ -288,13 +272,42 @@
                             ((uint32_t) buffer[0x17] << 16) |
                             ((uint32_t) buffer[0x18] << 24);
     
+    if(sectors_per_fat == 0)
+        /* this is not a FAT16 */
+        return 0;
+
+    if(sector_count == 0)
+    {
+        if(sector_count_16 == 0)
+            /* illegal volume size */
+            return 0;
+        else
+            sector_count = sector_count_16;
+    }
+
+    /* ensure we really have a FAT16 fs here */
+    uint32_t data_sector_count = sector_count
+                                 - reserved_sectors
+                                 - (uint32_t) sectors_per_fat * fat_copies
+                                 - ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector);
+    uint32_t data_cluster_count = data_sector_count / sectors_per_cluster;
+    if(data_cluster_count < 4085 || data_cluster_count >= 65525)
+        /* this is not a FAT16 */
+        return 0;
+
+    partition->type = PARTITION_TYPE_FAT16;
+
+    /* fill header information */
+    struct fat16_header_struct* header = &fs->header;
+    memset(header, 0, sizeof(*header));
+    
     header->size = sector_count * bytes_per_sector;
 
     header->fat_offset = /* jump to partition */
                          partition_offset +
                          /* jump to fat */
                          (uint32_t) reserved_sectors * bytes_per_sector;
-    header->fat_size = (uint32_t) sectors_per_fat * bytes_per_sector;
+    header->fat_size = (data_cluster_count + 2) * 2;
 
     header->sector_size = bytes_per_sector;
     header->cluster_size = (uint32_t) bytes_per_sector * sectors_per_cluster;
@@ -730,7 +743,7 @@
             }
 
             if(!device_write(fat_offset + 2 * cluster_new, buffer, sizeof(buffer)))
-                return 0;
+                break;
 
             cluster_next = cluster_new;
             if(--count_left == 0)
@@ -816,9 +829,12 @@
         /* free cluster */
         buffer[0] = FAT16_CLUSTER_FREE & 0xff;
         buffer[1] = (FAT16_CLUSTER_FREE >> 8) & 0xff;
-        if(!fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2))
-            return 0;
+        fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2);
 
+        /* We continue in any case here, even if freeing the cluster failed.
+         * The cluster is lost, but maybe we can still free up some later ones.
+         */
+
         cluster_num = cluster_num_next;
     }
 
@@ -1171,6 +1187,7 @@
  */
 uint8_t fat16_resize_file(struct fat16_file_struct* fd, uint32_t size)
 {
+#if FAT16_WRITE_SUPPORT
     if(!fd)
         return 0;
 
@@ -1209,13 +1226,8 @@
             }
         }
 
-        if(size_new == 0)
+        if(size_new > 0)
         {
-            /* free all clusters no longer needed */
-            fat16_free_clusters(fd->fs, cluster_num);
-        }
-        else
-        {
             /* Allocate new cluster chain and append
              * it to the existing one, if available.
              */
@@ -1233,6 +1245,19 @@
             }
         }
 
+        /* write new directory entry */
+        fd->dir_entry.file_size = size;
+        if(size == 0)
+            fd->dir_entry.cluster = 0;
+        if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry))
+            return 0;
+
+        if(size_new == 0)
+        {
+            /* free all clusters no longer needed */
+            fat16_free_clusters(fd->fs, cluster_num);
+        }
+
     } while(0);
 
     /* correct file position */
@@ -1242,14 +1267,10 @@
         fd->pos_cluster = 0;
     }
 
-    /* write new directory entry */
-    fd->dir_entry.file_size = size;
-    if(size == 0)
-        fd->dir_entry.cluster = 0;
-    if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry))
-        return 0;
-
     return 1;
+#else
+    return 0;
+#endif
 }
 
 /**
@@ -1684,9 +1705,7 @@
     /* We deleted the directory entry. The next thing to do is
      * marking all occupied clusters as free.
      */
-    fat16_free_clusters(fs, dir_entry->cluster);
-    
-    return 1;
+    return fat16_free_clusters(fs, dir_entry->cluster);
 #else
     return 0;
 #endif
@@ -1704,7 +1723,7 @@
     if(!fs)
         return 0;
 
-    return fs->header.fat_size / 2 * fs->header.cluster_size;
+    return (fs->header.fat_size / 2 - 2) * fs->header.cluster_size;
 }
 
 /**
Index: main.c
===================================================================
--- main.c	(.../sd-reader_release_20060816)	(Revision 106)
+++ main.c	(.../sd-reader_release_20060824)	(Revision 106)
@@ -8,6 +8,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <avr/pgmspace.h>
+#include <avr/sleep.h>
 #include "fat16.h"
 #include "fat16_config.h"
 #include "partition.h"
@@ -59,7 +60,7 @@
  * - <tt>cd \<directory\></tt>\n
  *   Changes current working directory to \<directory\>.
  * - <tt>disk</tt>\n
- *   Shows FAT16 filesystem capacity and free storage.
+ *   Shows card manufacturer, status, filesystem capacity and free storage space.
  * - <tt>ls</tt>\n
  *   Shows the content of the current directory.
  * - <tt>rm \<file\></tt>\n
@@ -85,12 +86,12 @@
  *     </tr>
  *     <tr>
  *         <td>MMC/SD (read-only)</td>
- *         <td align="right">1034</td>
+ *         <td align="right">1570</td>
  *         <td align="right">0</td>
  *     </tr>
  *     <tr>
  *         <td>MMC/SD (read-write)</td>
- *         <td align="right">1486</td>
+ *         <td align="right">2022</td>
  *         <td align="right">517</td>
  *     </tr>
  *     <tr>
@@ -100,12 +101,12 @@
  *     </tr>
  *     <tr>
  *         <td>FAT16 (read-only)</td>
- *         <td align="right">3888</td>
+ *         <td align="right">3722</td>
  *         <td align="right">0</td>
  *     </tr>
  *     <tr>
  *         <td>FAT16 (read-write)</td>
- *         <td align="right">6920</td>
+ *         <td align="right">7024</td>
  *         <td align="right">0</td>
  *     </tr>
  * </table>
@@ -178,12 +179,16 @@
  * the Free Software Foundation (http://www.gnu.org/copyleft/gpl.html).
  */
 
-uint8_t read_line(char* buffer, uint8_t buffer_length);
-uint8_t find_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* dir_entry);
-struct fat16_file_struct* open_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name); 
+static uint8_t read_line(char* buffer, uint8_t buffer_length);
+static uint8_t find_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* dir_entry);
+static struct fat16_file_struct* open_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name); 
+static uint8_t print_disk_info(const struct fat16_fs_struct* fs);
 
 int main()
 {
+    /* we will just use ordinary idle mode */
+    set_sleep_mode(SLEEP_MODE_IDLE);
+
     /* setup uart */
     uart_init();
     /* setup stdio */
@@ -246,6 +251,9 @@
         return 1;
     }
     
+    /* print some card information as a boot message */
+    print_disk_info(fs);
+
     /* provide a simple shell */
     char buffer[24];
     while(1)
@@ -331,7 +339,8 @@
         }
         else if(strcmp_P(command, PSTR("disk")) == 0)
         {
-            printf_P(PSTR("disk total: %ld free: %ld\n"), fat16_get_fs_size(fs), fat16_get_fs_free(fs));
+            if(!print_disk_info(fs))
+                printf_P(PSTR("error reading disk info\n"));
         }
 #if FAT16_WRITE_SUPPORT
         else if(strncmp_P(command, PSTR("rm "), 3) == 0)
@@ -500,3 +509,27 @@
     return fat16_open_file(fs, &file_entry);
 }
 
+uint8_t print_disk_info(const struct fat16_fs_struct* fs)
+{
+    if(!fs)
+        return 0;
+
+    struct sd_raw_info disk_info;
+    if(!sd_raw_get_info(&disk_info))
+        return 0;
+
+    printf_P(PSTR("manuf:  0x%02x\n"), disk_info.manufacturer);
+    printf_P(PSTR("oem:    %s\n"), disk_info.oem);
+    printf_P(PSTR("prod:   %s\n"), disk_info.product);
+    printf_P(PSTR("rev:    %02x\n"), disk_info.revision);
+    printf_P(PSTR("serial: 0x%08lx\n"), disk_info.serial);
+    printf_P(PSTR("date:   %02d/%02d\n"), disk_info.manufacturing_month, disk_info.manufacturing_year);
+    printf_P(PSTR("size:   %ld\n"), disk_info.capacity);
+    printf_P(PSTR("copy:   %d\n"), disk_info.flag_copy);
+    printf_P(PSTR("wr.pr.: %d/%d\n"), disk_info.flag_write_protect_temp, disk_info.flag_write_protect);
+    printf_P(PSTR("format: %d\n"), disk_info.format);
+    printf_P(PSTR("free:   %ld/%ld\n"), fat16_get_fs_free(fs), fat16_get_fs_size(fs));
+
+    return 1;
+}
+
Index: sd_raw.h
===================================================================
--- sd_raw.h	(.../sd-reader_release_20060816)	(Revision 106)
+++ sd_raw.h	(.../sd-reader_release_20060824)	(Revision 106)
@@ -22,6 +22,96 @@
  * \author Roland Riegel
  */
 
+/**
+ * The card's layout is harddisk-like, which means it contains
+ * a master boot record with a partition table.
+ */
+#define SD_RAW_FORMAT_HARDDISK 0
+/**
+ * The card contains a single filesystem and no partition table.
+ */
+#define SD_RAW_FORMAT_SUPERFLOPPY 1
+/**
+ * The card's layout follows the Universal File Format.
+ */
+#define SD_RAW_FORMAT_UNIVERSAL 2
+/**
+ * The card's layout is unknown.
+ */
+#define SD_RAW_FORMAT_UNKNOWN 3
+
+/**
+ * This struct is used by sd_raw_get_info() to return
+ * manufacturing and status information of the card.
+ */
+struct sd_raw_info
+{
+    /**
+     * A manufacturer code globally assigned by the SD card organization.
+     */
+    uint8_t manufacturer;
+    /**
+     * A string describing the card's OEM or content, globally assigned by the SD card organization.
+     */
+    uint8_t oem[3];
+    /**
+     * A product name.
+     */
+    uint8_t product[6];
+    /**
+     * The card's revision, coded in packed BCD.
+     *
+     * For example, the revision value \c 0x32 means "3.2".
+     */
+    uint8_t revision;
+    /**
+     * A serial number assigned by the manufacturer.
+     */
+    uint32_t serial;
+    /**
+     * The year of manufacturing.
+     *
+     * A value of zero means year 2000.
+     */
+    uint8_t manufacturing_year;
+    /**
+     * The month of manufacturing.
+     */
+    uint8_t manufacturing_month;
+    /**
+     * The card's total capacity in bytes.
+     */
+    uint32_t capacity;
+    /**
+     * Defines wether the card's content is original or copied.
+     *
+     * A value of \c 0 means original, \c 1 means copied.
+     */
+    uint8_t flag_copy;
+    /**
+     * Defines wether the card's content is write-protected.
+     *
+     * \note This is an internal flag and does not represent the
+     *       state of the card's mechanical write-protect switch.
+     */
+    uint8_t flag_write_protect;
+    /**
+     * Defines wether the card's content is temporarily write-protected.
+     *
+     * \note This is an internal flag and does not represent the
+     *       state of the card's mechanical write-protect switch.
+     */
+    uint8_t flag_write_protect_temp;
+    /**
+     * The card's data layout.
+     *
+     * See the \c SD_RAW_FORMAT_* constants for details.
+     *
+     * \note This value is not guaranteed to match reality.
+     */
+    uint8_t format;
+};
+
 typedef uint8_t (*sd_raw_interval_handler)(uint8_t* buffer, uint32_t offset, void* p);
 
 uint8_t sd_raw_init();
@@ -33,6 +123,8 @@
 uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length);
 uint8_t sd_raw_sync();
 
+uint8_t sd_raw_get_info(struct sd_raw_info* info);
+
 /**
  * @}
  */
Index: ChangeLog
===================================================================
--- ChangeLog	(.../sd-reader_release_20060816)	(Revision 106)
+++ ChangeLog	(.../sd-reader_release_20060824)	(Revision 106)
@@ -1,4 +1,11 @@
 
+2006-08-24 sd-reader
+	* Improve sleep handling.
+	* Display extended card information on boot and
+	  when executing the "disk" shell command.
+	* Correctly determine FAT type by cluster count.
+	* Fix cluster allocation beyond card capacity.
+
 2006-08-16 sd-reader
 	* Provide FAT16 capacity and usage information.
 	* Implement the backspace key in the mini shell.
Index: uart.c
===================================================================
--- uart.c	(.../sd-reader_release_20060816)	(Revision 106)
+++ uart.c	(.../sd-reader_release_20060824)	(Revision 106)
@@ -75,7 +75,6 @@
     UCSRB = (1 << RXEN) | (1 << TXEN);
 #else
     UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
-    sei();
 #endif
 }
 
@@ -121,17 +120,13 @@
 {
     /* wait until receive buffer is full */
 #if USE_SLEEP
-    set_sleep_mode(SLEEP_MODE_IDLE);
-    cli();
-    while(!(UCSRA & (1 << RXC)))
-    {
-        sleep_enable();
-        sei();
-        sleep_cpu();
-        cli();
-        sleep_disable();
-    }
+    uint8_t sreg = SREG;
     sei();
+
+    while(!(UCSRA & (1 << RXC)))
+        sleep_mode();
+
+    SREG = sreg;
 #else
     while(!(UCSRA & (1 << RXC)));
 #endif
Index: Makefile
===================================================================
--- Makefile	(.../sd-reader_release_20060816)	(Revision 106)
+++ Makefile	(.../sd-reader_release_20060824)	(Revision 106)
@@ -16,7 +16,7 @@
 SIZE := avr-size -A
 DOXYGEN := doxygen
 
-CFLAGS := -Wall -pedantic -mmcu=$(MCU) -std=c99 -Os -DF_CPU=$(MCU_FREQ)
+CFLAGS := -Wall -pedantic -mmcu=$(MCU) -std=c99 -g -Os -DF_CPU=$(MCU_FREQ)
 
 all: $(HEX)
 
