devsd: Convert to new blkdev API and support rawflag=1
authorWill Sowerbutts <will@sowerbutts.com>
Sun, 25 Jan 2015 22:00:34 +0000 (22:00 +0000)
committerWill Sowerbutts <will@sowerbutts.com>
Sun, 25 Jan 2015 22:00:34 +0000 (22:00 +0000)
Kernel/dev/devsd.c
Kernel/dev/devsd.h

index 238c664..b4dff17 100644 (file)
@@ -2,6 +2,7 @@
 /* Fuzix SD card driver                                                  */
 /* 2014-12-28 Will Sowerbutts                                            */
 /* 2015-01-04 WRS updated to new blkdev API                              */
+/* 2015-01-25 WRS updated to newer blkdev API                            */
 /*                                                                       */
 /* Based on UZI-socz80 SD card driver, which was itself based on:        */
 /*   MMCv3/SDv1/SDv2 (in SPI mode) control module  (C)ChaN, 2007         */
@@ -23,26 +24,39 @@ static uint8_t sd_card_type[SD_DRIVE_COUNT];
 static void sd_init_drive(uint8_t drive);
 static int sd_spi_init(uint8_t drive);
 static void sd_spi_release(uint8_t drive);
-static int sd_spi_wait_ready(uint8_t drive);
-static bool sd_spi_transmit_sector(uint8_t drive, void *ptr, unsigned int length);
-static bool sd_spi_receive_sector(uint8_t drive, void *ptr, unsigned int length);
+static bool sd_spi_wait_ready(uint8_t drive);
+static bool sd_spi_receive_prepare(uint8_t drive);
 static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg);
-static uint32_t sd_get_size_sectors(uint8_t drive);
 
-static bool devsd_transfer_sector(uint8_t drive, uint32_t lba, void *buffer, bool read_notwrite)
+static uint8_t devsd_transfer_sector(void)
 {
-    uint8_t attempt;
+    uint8_t attempt, drive, reply;
     bool success;
 
-    if(!(sd_card_type[drive] & CT_BLOCK))
-       lba <<= 9; /* multiply by 512 to convert block to byte address */
+    drive = blk_op.blkdev->driver_data & DRIVE_NR_MASK;
 
     for(attempt=0; attempt<8; attempt++){
-       if(sd_send_command(drive, read_notwrite ? CMD17 : CMD24, lba) == 0){
-           if(read_notwrite)
-               success = sd_spi_receive_sector(drive, buffer, 512);
-           else
-               success = sd_spi_transmit_sector(drive, buffer, 512);
+       if(sd_send_command(drive, blk_op.is_read ? CMD17 : CMD24, 
+                    /* for byte addressed cards, shift LBA to convert to byte address */
+                    (blk_op.blkdev->driver_data & CT_BLOCK) ? blk_op.lba : (blk_op.lba << 9)
+                    ) == 0){
+           if(blk_op.is_read){
+                success = sd_spi_receive_prepare(drive);
+                if(success)
+                    sd_spi_receive_sector(drive);
+            }else{
+                success = false;
+                if(sd_spi_wait_ready(drive)){
+                    sd_spi_transmit_byte(drive, 0xFE);
+                    sd_spi_transmit_sector(drive);
+                    sd_spi_transmit_byte(drive, 0xFF); /* dummy CRC */
+                    sd_spi_transmit_byte(drive, 0xFF);
+                    reply = sd_spi_receive_byte(drive);
+                    if((reply & 0x1f) != 0x05)
+                        return false; /* failed */
+                    return true; /* hooray! */
+                }
+            }
        }else
            success = false;
 
@@ -55,7 +69,7 @@ static bool devsd_transfer_sector(uint8_t drive, uint32_t lba, void *buffer, boo
     }
 
     udata.u_error = EIO;
-    return -1;
+    return 0;
 }
 
 static void sd_spi_release(uint8_t drive)
@@ -64,42 +78,28 @@ static void sd_spi_release(uint8_t drive)
     sd_spi_receive_byte(drive);
 }
 
-static int sd_spi_wait_ready(uint8_t drive)
+static bool sd_spi_wait_ready(uint8_t drive)
 {
-    unsigned char res;
+    uint8_t res;
     timer_t timer;
 
-    timer = set_timer_ms(100);
+    timer = set_timer_ms(500);
     sd_spi_receive_byte(drive);
-    do{
+
+    while(true){
         res = sd_spi_receive_byte(drive);
+        if(res == 0xFF)
+            return true;
         if(timer_expired(timer)){
-            kputs("sd_spi_wait_ready: timeout\n");
+            kputs("sd: timeout\n");
             break;
         }
-    }while ((res != 0xFF));
-
-    return res;
-}
+    }
 
-static bool sd_spi_transmit_sector(uint8_t drive, void *ptr, unsigned int length)
-{
-    unsigned char reply;
-
-    if(sd_spi_wait_ready(drive) != 0xFF)
-        return false; /* failed */
-
-    sd_spi_transmit_byte(drive, 0xFE);
-    sd_spi_transmit_block(drive, ptr, length);
-    sd_spi_transmit_byte(drive, 0xFF); /* dummy CRC */
-    sd_spi_transmit_byte(drive, 0xFF);
-    reply = sd_spi_receive_byte(drive);
-    if((reply & 0x1f) != 0x05)
-        return false; /* failed */
-    return true; /* hooray! */
+    return false;
 }
 
-static bool sd_spi_receive_sector(uint8_t drive, void *ptr, unsigned int length)
+static bool sd_spi_receive_prepare(uint8_t drive)
 {
     unsigned int timer;
     unsigned char b;
@@ -109,15 +109,12 @@ static bool sd_spi_receive_sector(uint8_t drive, void *ptr, unsigned int length)
     do{
         b = sd_spi_receive_byte(drive);
         if(timer_expired(timer)){
-            kputs("sd_spi_receive_sector: timeout\n");
+            kputs("sd: timeout\n");
             return false;
         }
     }while(b == 0xFF);
 
-    if(b != 0xFE)
-        return false; /* failed */
-
-    return sd_spi_receive_block(drive, ptr, length); /* returns true on success */
+    return (b == 0xFE); /* true on success */
 }
 
 static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg)
@@ -134,7 +131,7 @@ static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg)
     /* Select the card and wait for ready */
     sd_spi_raise_cs(drive);
     sd_spi_lower_cs(drive);
-    if (sd_spi_wait_ready(drive) != 0xFF) 
+    if(!sd_spi_wait_ready(drive))
         return 0xFF;
 
     /* Send command packet */
@@ -146,11 +143,11 @@ static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg)
     sd_spi_transmit_byte(drive, (unsigned char)arg);         /* Argument[7..0] */
 #else
     /* sdcc sadly unable to figure this out for itself yet */
-    p = (unsigned char *)&arg;
-    sd_spi_transmit_byte(drive, p[3]);                       /* Argument[31..24] */
-    sd_spi_transmit_byte(drive, p[2]);                       /* Argument[23..16] */
-    sd_spi_transmit_byte(drive, p[1]);                       /* Argument[15..8] */
-    sd_spi_transmit_byte(drive, p[0]);                       /* Argument[7..0] */
+    p = ((unsigned char *)&arg)+3;
+    sd_spi_transmit_byte(drive, *(p--));                     /* Argument[31..24] */
+    sd_spi_transmit_byte(drive, *(p--));                     /* Argument[23..16] */
+    sd_spi_transmit_byte(drive, *(p--));                     /* Argument[15..8] */
+    sd_spi_transmit_byte(drive, *p);                         /* Argument[7..0] */
 #endif
     /* there's only a few commands (in native mode) that need correct CRCs */
     n = 0x01;                                                /* Dummy CRC + Stop */
@@ -188,29 +185,43 @@ void devsd_init(void)
 static void sd_init_drive(uint8_t drive)
 {
     blkdev_t *blk;
-    uint32_t sector_count;
+    unsigned char csd[16], n;
+    uint8_t card_type;
 
     kprintf("SD drive %d: ", drive);
-    sd_card_type[drive] = sd_spi_init(drive);
+    card_type = sd_spi_init(drive);
 
-    if(!(sd_card_type[drive] & (~CT_BLOCK))){
+    if(!(card_type & (~CT_BLOCK))){
         kprintf("no card found\n");
         return;
     }
+
+    blk = blkdev_alloc();
+    if(!blk)
+        return;
+
+    blk->transfer = devsd_transfer_sector;
+    blk->driver_data = (drive & DRIVE_NR_MASK) | card_type;
     
     /* read and compute card size */
-    sector_count = sd_get_size_sectors(drive);
-    if(!sector_count){
-        kputs("weird card\n");
-        return;
-    }
-    blk = blkdev_alloc();
-    if (blk) {
-        blk->transfer = devsd_transfer_sector;
-        blk->drive_number = drive;
-        blk->drive_lba_count = sector_count;
-        blkdev_scan(blk, 0);
+    if(sd_send_command(drive, CMD9, 0) == 0 && sd_spi_receive_prepare(drive)){
+        for(n=0; n<16; n++)
+            csd[n] = sd_spi_receive_byte(drive);
+        if ((csd[0] >> 6) == 1) {
+            /* SDC ver 2.00 */
+            blk->drive_lba_count = ((uint32_t)csd[9] 
+                                   + (uint32_t)((unsigned int)csd[8] << 8) + 1) << 10;
+        } else {
+            /* SDC ver 1.XX or MMC*/
+            n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
+            blk->drive_lba_count = (csd[8] >> 6) + ((unsigned int)csd[7] << 2) 
+                                   + ((unsigned int)(csd[6] & 3) << 10) + 1;
+            blk->drive_lba_count <<= (n-9);
+        }
     }
+    sd_spi_release(drive);
+
+    blkdev_scan(blk, 0);
 }
 
 static int sd_spi_init(uint8_t drive)
@@ -224,7 +235,7 @@ static int sd_spi_init(uint8_t drive)
     for (n = 20; n; n--)
         sd_spi_receive_byte(drive); /* 160 dummy clocks */
 
-    card_type = 0;
+    card_type = CT_NONE;
     /* Enter Idle state */
     if (sd_send_command(drive, CMD0, 0) == 1) {
         /* initialisation timeout 1 second */
@@ -256,7 +267,7 @@ static int sd_spi_init(uint8_t drive)
             while(!timer_expired(timer) && sd_send_command(drive, cmd, 0));
             /* Set R/W block length to 512 */
             if(timer_expired || sd_send_command(drive, CMD16, 512) != 0)
-                card_type = 0;
+                card_type = CT_NONE;
         }
     }
     sd_spi_release(drive);
@@ -266,23 +277,5 @@ static int sd_spi_init(uint8_t drive)
         return card_type;
     }
 
-    return 0; /* failed */
-}
-
-static uint32_t sd_get_size_sectors(uint8_t drive)
-{
-    unsigned char csd[16], n;
-    uint32_t sectors = 0;
-
-    if(sd_send_command(drive, CMD9, 0) == 0 && sd_spi_receive_sector(drive, csd, 16)){
-        if ((csd[0] >> 6) == 1) {      /* SDC ver 2.00 */
-            sectors = ((uint32_t)csd[9] + (uint32_t)((unsigned int)csd[8] << 8) + 1) << 10;
-        } else {                                       /* SDC ver 1.XX or MMC*/
-            n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
-            sectors = (csd[8] >> 6) + ((unsigned int)csd[7] << 2) + ((unsigned int)(csd[6] & 3) << 10) + 1;
-            sectors = sectors << (n - 9);
-        }
-    }
-    sd_spi_release(drive);
-    return sectors;
+    return CT_NONE; /* failed */
 }
index 840015b..997b332 100644 (file)
@@ -6,11 +6,26 @@
    Define DEVICE_SD if SD hardware is present on your platform.
 
    Define SD_DRIVE_COUNT to the number of SD cards your hardware
-   supports (range 1--4).
+   supports (at most 16)
 
    Provide the platform-specific SPI functions listed below to
    drive the SPI bus on your hardware, for an example of how to
    do this see platform-n8vem-mark4/devsdspi.c
+
+   The required functions are:
+
+    - sd_spi_clock(): switch between a slow clock (100--400kHz) for
+    initialisation, and a fast (up to 20--25MHz) for normal operation.
+
+    - sd_spi_raise_cs(), sd_spi_lower_cs(): raise or lower the CS line.
+
+    - sd_spi_transmit_byte(): transmit a single byte
+
+    - sd_spi_receive_byte(): receive a single byte
+
+    - sd_spi_transmit_sector(): transmit a 512-byte sector (params in blk_op)
+
+    - sd_spi_receive_sector(): receive a 512-byte sector (params in blk_op)
 */
 
 
@@ -23,8 +38,8 @@ void sd_spi_raise_cs(uint8_t drive);
 void sd_spi_lower_cs(uint8_t drive);
 void sd_spi_transmit_byte(uint8_t drive, uint8_t byte);
 uint8_t sd_spi_receive_byte(uint8_t drive);
-bool sd_spi_receive_block(uint8_t drive, uint8_t *ptr, unsigned int length);
-bool sd_spi_transmit_block(uint8_t drive, uint8_t *ptr, unsigned int length);
+bool sd_spi_receive_sector(uint8_t drive);
+bool sd_spi_transmit_sector(uint8_t drive);
 
 /* Definitions for MMC/SDC command */
 #define CMD0    (0x40+0)    /* GO_IDLE_STATE */
@@ -45,11 +60,15 @@ bool sd_spi_transmit_block(uint8_t drive, uint8_t *ptr, unsigned int length);
 #define CMD55   (0x40+55)   /* APP_CMD */
 #define CMD58   (0x40+58)   /* READ_OCR */
 
-#define CT_NONE 0x00
-#define CT_MMC 0x01
-#define CT_SD1 0x02
-#define CT_SD2 0x04
-#define CT_SDC (CT_SD1|CT_SD2)
-#define CT_BLOCK 0x08
+/* Use the top four bits of driver_data field of blkdev_t for the card type */
+#define CT_NONE  0x00
+#define CT_MMC   0x10
+#define CT_SD1   0x20
+#define CT_SD2   0x40
+#define CT_BLOCK 0x80 /* set if block addressed, unset if byte addressed */
+#define CT_SDC   (CT_SD1|CT_SD2)
+
+/* Low four bits of driver_data are available to store drive number */
+#define DRIVE_NR_MASK 0x0F
 
 #endif /* __DEVSD_DOT_H__ */