1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
//! Provides driver for accessing an SD Card and a userspace Driver.
//!
//! This allows initialization and block reads or writes on top of SPI.
//!
//! Usage
//! -----
//!
//! ```rust
//! let sdcard_spi = static_init!(
//!     capsules::virtual_spi::VirtualSpiMasterDevice<'static, usart::USART>,
//!     capsules::virtual_spi::VirtualSpiMasterDevice::new(mux_spi,
//!                                                        Some(&sam4l::gpio::PA[13])));
//! let sdcard_virtual_alarm = static_init!(
//!     VirtualMuxAlarm<'static, sam4l::ast::Ast>,
//!     VirtualMuxAlarm::new(mux_alarm));
//!
//! let sdcard = static_init!(
//!     capsules::sdcard::SDCard<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast>>,
//!     capsules::sdcard::SDCard::new(sdcard_spi,
//!                                   sdcard_virtual_alarm,
//!                                   Some(&sam4l::gpio::PA[17]),
//!                                   &mut capsules::sdcard::TXBUFFER,
//!                                   &mut capsules::sdcard::RXBUFFER));
//! sdcard_spi.set_client(sdcard);
//! sdcard_virtual_alarm.set_client(sdcard);
//! sam4l::gpio::PA[17].set_client(sdcard);
//!
//! let sdcard_driver = static_init!(
//!     capsules::sdcard::SDCardDriver<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast>>,
//!     capsules::sdcard::SDCardDriver::new(sdcard, &mut capsules::sdcard::KERNEL_BUFFER));
//! sdcard.set_client(sdcard_driver);
//! ```

// Resources for SD Card API:
//  * elm-chan.org/docs/mmc/mmc_e.html
//  * alumni.cs.ucr.edu/~amitra/sdcard/Additional/sdcard_appnote_foust.pdf
//  * luckyresistor.me/cat-protector/software/sdcard-2/
//  * http://users.ece.utexas.edu/~valvano/EE345M/SD_Physical_Layer_Spec.pdf

use core::cell::Cell;
use core::cmp;
use kernel::{AppId, AppSlice, Callback, Driver, ReturnCode, Shared};
use kernel::common::take_cell::{MapCell, TakeCell};
use kernel::hil;
use kernel::hil::time::Frequency;

/// Buffers used for SD card transactions, assigned in board `main.rs` files
/// Constraints:
///
///  * RXBUFFER must be greater than or equal to TXBUFFER in length
///  * Both RXBUFFER and TXBUFFER must be longer  than the SD card's block size
pub static mut TXBUFFER: [u8; 515] = [0; 515];
pub static mut RXBUFFER: [u8; 515] = [0; 515];

/// SD Card capsule, capable of being built on top of by other kernel capsules
pub struct SDCard<'a, A: hil::time::Alarm + 'a> {
    spi: &'a hil::spi::SpiMasterDevice,
    state: Cell<SpiState>,
    after_state: Cell<SpiState>,

    alarm: &'a A,
    alarm_state: Cell<AlarmState>,
    alarm_count: Cell<u8>,

    is_initialized: Cell<bool>,
    card_type: Cell<SDCardType>,

    detect_pin: Cell<Option<&'static hil::gpio::Pin>>,

    txbuffer: TakeCell<'static, [u8]>,
    rxbuffer: TakeCell<'static, [u8]>,

    client: Cell<Option<&'static SDCardClient>>,
    client_buffer: TakeCell<'static, [u8]>,
    client_offset: Cell<usize>,
}

/// SD card command codes
#[allow(dead_code, non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq)]
enum SDCmd {
    CMD0_Reset = 0,                       //                  Reset
    CMD1_Init = 1,                        //                   Generic init
    CMD8_CheckVoltage = 8,                //           Check voltage range
    CMD9_ReadCSD = 9,                     //                Read chip specific data (CSD) register
    CMD12_StopRead = 12,                  //             Stop multiple block read
    CMD16_SetBlockSize = 16,              //         Set blocksize
    CMD17_ReadSingle = 17,                //           Read single block
    CMD18_ReadMultiple = 18,              //         Read multiple blocks
    CMD24_WriteSingle = 24,               //          Write single block
    CMD25_WriteMultiple = 25,             //        Write multiple blocks
    CMD55_ManufSpecificCommand = 55,      // Next command will be manufacturer specific
    CMD58_ReadOCR = 58,                   //              Read operation condition register (OCR)
    ACMD41_ManufSpecificInit = 0x80 + 41, // Manufacturer specific Init
}

/// SD card response codes
#[allow(dead_code, non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq)]
enum SDResponse {
    R1_Status,         //         Status response, single byte
    R2_ExtendedStatus, // Extended response, two bytes, unused in practice
    R3_OCR,            //            OCR response, status + four bytes
    R7_CheckVoltage,   //   Check voltage response, status + four bytes
}

/// SPI states
#[derive(Clone, Copy, Debug, PartialEq)]
enum SpiState {
    Idle,

    SendManufSpecificCmd { cmd: SDCmd, arg: u32 },

    InitReset,
    InitCheckVersion,
    InitRepeatHCSInit,
    InitCheckCapacity,
    InitAppSpecificInit,
    InitRepeatAppSpecificInit,
    InitRepeatGenericInit,
    InitSetBlocksize,
    InitComplete,

    StartReadBlocks { count: u32 },
    WaitReadBlock,
    ReadBlockComplete,
    WaitReadBlocks { count: u32 },
    ReceivedBlock { count: u32 },
    ReadBlocksComplete,

    StartWriteBlocks { count: u32 },
    WriteBlockResponse,
    WriteBlockBusy,
    WaitWriteBlockBusy,
}

/// Alarm states
#[derive(Clone, Copy, Debug, PartialEq)]
enum AlarmState {
    Idle,

    DetectionChange,

    RepeatHCSInit,
    RepeatAppSpecificInit,
    RepeatGenericInit,

    WaitForDataBlock,
    WaitForDataBlocks { count: u32 },

    WaitForWriteBusy,
}

/// Error codes returned if an SD card transaction fails
#[derive(Clone, Copy, Debug, PartialEq)]
enum ErrorCode {
    CardStateChanged = -1,
    InitializationFailure = -2,
    ReadFailure = -3,
    WriteFailure = -4,
    TimeoutFailure = -5,
}

/// SD card types, determined during initialization
#[derive(Clone, Copy, Debug, PartialEq)]
enum SDCardType {
    Uninitialized = 0x00,
    MMC = 0x01,
    SDv1 = 0x02,
    SDv2 = 0x04,
    SDv2BlockAddressable = 0x04 | 0x08,
}

// Constants used in driver
const SUCCESS_STATUS: u8 = 0x00;
const INITIALIZING_STATUS: u8 = 0x01;
const DATA_TOKEN: u8 = 0xFE;

/// Callback functions from SDCard
pub trait SDCardClient {
    fn card_detection_changed(&self, installed: bool);
    fn init_done(&self, block_size: u32, total_size: u64);
    fn read_done(&self, data: &'static mut [u8], len: usize);
    fn write_done(&self, buffer: &'static mut [u8]);
    fn error(&self, error: u32);
}

/// Functions for initializing and accessing an SD card
impl<'a, A: hil::time::Alarm + 'a> SDCard<'a, A> {
    /// Create a new SD card interface
    ///
    /// spi - virtualized SPI to use for communication with SD card
    /// alarm - virtualized Timer with a granularity of at least 1 ms
    /// detect_pin - active low GPIO pin used to detect if an SD card is
    ///     installed
    /// txbuffer - buffer for holding SPI write data, at least 515 bytes in
    ///     length
    /// rxbuffer - buffer for holding SPI read data, at least 515 bytes in
    ///     length
    pub fn new(
        spi: &'a hil::spi::SpiMasterDevice,
        alarm: &'a A,
        detect_pin: Option<&'static hil::gpio::Pin>,
        txbuffer: &'static mut [u8; 515],
        rxbuffer: &'static mut [u8; 515],
    ) -> SDCard<'a, A> {
        // initialize buffers
        for byte in txbuffer.iter_mut() {
            *byte = 0xFF;
        }
        for byte in rxbuffer.iter_mut() {
            *byte = 0xFF;
        }

        // handle optional detect pin
        let pin = detect_pin.map_or(None, |pin| {
            pin.make_input();
            Some(pin)
        });

        // set up and return struct
        SDCard {
            spi: spi,
            state: Cell::new(SpiState::Idle),
            after_state: Cell::new(SpiState::Idle),
            alarm: alarm,
            alarm_state: Cell::new(AlarmState::Idle),
            alarm_count: Cell::new(0),
            is_initialized: Cell::new(false),
            card_type: Cell::new(SDCardType::Uninitialized),
            detect_pin: Cell::new(pin),
            txbuffer: TakeCell::new(txbuffer),
            rxbuffer: TakeCell::new(rxbuffer),
            client: Cell::new(None),
            client_buffer: TakeCell::empty(),
            client_offset: Cell::new(0),
        }
    }

    fn set_spi_slow_mode(&self) {
        // need to be in slow mode while initializing the SD card
        // set to CPHA=0, CPOL=0, 400 kHZ
        self.spi.configure(
            hil::spi::ClockPolarity::IdleLow,
            hil::spi::ClockPhase::SampleLeading,
            400000,
        );
    }

    fn set_spi_fast_mode(&self) {
        // can read/write in fast mode after the SD card is initialized
        // set to CPHA=0, CPOL=0, 4 MHz
        self.spi.configure(
            hil::spi::ClockPolarity::IdleLow,
            hil::spi::ClockPhase::SampleLeading,
            4000000,
        );
    }

    /// send a command over SPI and collect the response
    /// Handles encoding of command, checksum, and padding bytes. The response
    /// still needs to be parsed out of the read_buffer when complete
    fn send_command(
        &self,
        cmd: SDCmd,
        arg: u32,
        write_buffer: &'static mut [u8],
        read_buffer: &'static mut [u8],
        recv_len: usize,
    ) {
        // Note: a good default recv_len is 10 bytes. Reading too many bytes
        //  rarely matters. However, it occasionally matters a lot, so we
        //  provide a settable recv_len

        if self.is_initialized() {
            // device is already initialized
            self.set_spi_fast_mode();
        } else {
            // device is still being initialized
            self.set_spi_slow_mode();
        }

        // send dummy bytes to start
        write_buffer[0] = 0xFF;
        write_buffer[1] = 0xFF;

        // command
        if (0x80 & cmd as u8) != 0x00 {
            // application-specific command
            write_buffer[2] = 0x40 | (0x7F & cmd as u8);
        } else {
            // normal command
            write_buffer[2] = 0x40 | cmd as u8;
        }

        // argument, MSB first
        write_buffer[3] = ((arg >> 24) & 0xFF) as u8;
        write_buffer[4] = ((arg >> 16) & 0xFF) as u8;
        write_buffer[5] = ((arg >> 8) & 0xFF) as u8;
        write_buffer[6] = ((arg >> 0) & 0xFF) as u8;

        // CRC is ignored except for CMD0 and maybe CMD8
        // Established practice it to just always use the CMD0 CRC unless we
        // are sending a CMD8
        if cmd == SDCmd::CMD8_CheckVoltage {
            write_buffer[7] = 0x87; // valid crc for CMD8(0x1AA)
        } else {
            write_buffer[7] = 0x95; // valid crc for CMD0
        }

        // append dummy bytes to transmission after command bytes
        // Limit to minimum length between write_buffer and recv_len
        for byte in write_buffer.iter_mut().skip(8).take(recv_len) {
            *byte = 0xFF;
        }

        // start SPI transaction
        // Length is command bytes (8) plus recv_len
        self.spi
            .read_write_bytes(write_buffer, Some(read_buffer), 8 + recv_len);
    }

    /// wrapper for easy reading of bytes over SPI
    fn read_bytes(
        &self,
        write_buffer: &'static mut [u8],
        read_buffer: &'static mut [u8],
        recv_len: usize,
    ) {
        self.set_spi_fast_mode();

        // set write buffer to null transactions
        // Limit to minimum length between write_buffer and recv_len.
        // Note: this could be optimized in the future by allowing SPI to read
        //  without a write buffer passed in
        for byte in write_buffer.iter_mut().take(recv_len) {
            *byte = 0xFF;
        }

        self.spi
            .read_write_bytes(write_buffer, Some(read_buffer), recv_len);
    }

    /// wrapper for easy writing of bytes over SPI
    fn write_bytes(
        &self,
        write_buffer: &'static mut [u8],
        read_buffer: &'static mut [u8],
        recv_len: usize,
    ) {
        self.set_spi_fast_mode();

        self.spi
            .read_write_bytes(write_buffer, Some(read_buffer), recv_len);
    }

    /// parse response bytes from SPI read buffer
    /// Unfortunately there is a variable amount of delay in SD card responses,
    /// so these bytes must be searched for
    fn get_response(&self, response: SDResponse, read_buffer: &[u8]) -> (u8, u8, u32) {
        let mut r1: u8 = 0xFF;
        let mut r2: u8 = 0xFF;
        let mut r3: u32 = 0xFFFFFFFF;

        // scan through read buffer for response byte
        for (i, &byte) in read_buffer.iter().enumerate() {
            if (byte & 0x80) == 0x00 {
                // status byte is always included
                r1 = byte;

                match response {
                    SDResponse::R2_ExtendedStatus => {
                        // status, then read/write status. Unused in practice
                        if i + 1 < read_buffer.len() {
                            r2 = read_buffer[i + 1];
                        }
                    }
                    SDResponse::R3_OCR | SDResponse::R7_CheckVoltage => {
                        // status, then Operating Condition Register
                        if i + 4 < read_buffer.len() {
                            r3 = (read_buffer[i + 1] as u32) << 24
                                | (read_buffer[i + 2] as u32) << 16
                                | (read_buffer[i + 3] as u32) << 8
                                | (read_buffer[i + 4] as u32);
                        }
                    }
                    _ => {
                        // R1, no bytes left to parse
                    }
                }

                // response found
                break;
            }
        }

        // return a tuple of the parsed bytes
        (r1, r2, r3)
    }

    /// updates SD card state on SPI transaction returns
    fn process_spi_states(
        &self,
        write_buffer: &'static mut [u8],
        read_buffer: &'static mut [u8],
        _: usize,
    ) {
        match self.state.get() {
            SpiState::SendManufSpecificCmd { cmd, arg } => {
                // send the application-specific command and resume the state
                //  machine
                self.state.set(self.after_state.get());
                self.after_state.set(SpiState::Idle);
                self.send_command(cmd, arg, write_buffer, read_buffer, 10);
            }

            SpiState::InitReset => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                // only continue if we are in idle state
                if r1 == INITIALIZING_STATUS {
                    // next send Check Voltage Range command that is only valid
                    //  on SDv2 cards. This is used to check which SD card
                    //  version is installed. Note that 0xAA is an arbitrary
                    //  check pattern that will be duplicated in the response
                    //  and 0x100 specifies that the card is running between
                    //  2.7 and 3.6 volts
                    self.state.set(SpiState::InitCheckVersion);
                    self.send_command(
                        SDCmd::CMD8_CheckVoltage,
                        0x1AA,
                        write_buffer,
                        read_buffer,
                        10,
                    );
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::InitializationFailure as u32);
                    });
                }
            }

            SpiState::InitCheckVersion => {
                // check response
                let (r1, _, r7) = self.get_response(SDResponse::R7_CheckVoltage, read_buffer);

                // look for test pattern duplicated in R7
                if r1 == INITIALIZING_STATUS && r7 == 0x1AA {
                    // we have an SDv2 card
                    // send application-specific initialization in high capacity mode (HCS)
                    self.state.set(SpiState::SendManufSpecificCmd {
                        cmd: SDCmd::ACMD41_ManufSpecificInit,
                        arg: 0x40000000,
                    });
                    self.after_state.set(SpiState::InitRepeatHCSInit);
                    self.send_command(
                        SDCmd::CMD55_ManufSpecificCommand,
                        0x0,
                        write_buffer,
                        read_buffer,
                        10,
                    );
                } else {
                    // we have either an SDv1 or MMCv3 card
                    // send application-specific initialization
                    self.state.set(SpiState::SendManufSpecificCmd {
                        cmd: SDCmd::ACMD41_ManufSpecificInit,
                        arg: 0x0,
                    });
                    self.after_state.set(SpiState::InitAppSpecificInit);
                    self.send_command(
                        SDCmd::CMD55_ManufSpecificCommand,
                        0x0,
                        write_buffer,
                        read_buffer,
                        10,
                    );
                }
            }

            SpiState::InitRepeatHCSInit => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    // card initialized
                    // check card capacity
                    self.alarm_count.set(0);
                    self.state.set(SpiState::InitCheckCapacity);
                    self.send_command(SDCmd::CMD58_ReadOCR, 0x0, write_buffer, read_buffer, 10);
                } else if r1 == INITIALIZING_STATUS {
                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // try again after 10 ms
                    self.alarm_state.set(AlarmState::RepeatHCSInit);
                    let interval = (10 as u32) * <A::Frequency>::frequency() / 1000;
                    let tics = self.alarm.now().wrapping_add(interval);
                    self.alarm.set_alarm(tics);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::InitializationFailure as u32);
                    });
                }
            }

            SpiState::InitCheckCapacity => {
                // check response
                let (r1, _, r7) = self.get_response(SDResponse::R3_OCR, read_buffer);

                if r1 == SUCCESS_STATUS {
                    if (r7 & 0x40000000) != 0x00000000 {
                        self.card_type.set(SDCardType::SDv2BlockAddressable);
                    } else {
                        self.card_type.set(SDCardType::SDv2);
                    }

                    // Read CSD register
                    // Note that the receive length needs to be increased here
                    //  to capture the 16-byte register (plus some slack)
                    self.state.set(SpiState::InitComplete);
                    self.send_command(SDCmd::CMD9_ReadCSD, 0x0, write_buffer, read_buffer, 28);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::InitializationFailure as u32);
                    });
                }
            }

            SpiState::InitAppSpecificInit => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == INITIALIZING_STATUS || r1 == SUCCESS_STATUS {
                    // SDv1 card
                    // send application-specific initialization
                    self.card_type.set(SDCardType::SDv1);
                    self.state.set(SpiState::SendManufSpecificCmd {
                        cmd: SDCmd::ACMD41_ManufSpecificInit,
                        arg: 0x0,
                    });
                    self.after_state.set(SpiState::InitRepeatAppSpecificInit);
                    self.send_command(
                        SDCmd::CMD55_ManufSpecificCommand,
                        0x0,
                        write_buffer,
                        read_buffer,
                        10,
                    );
                } else {
                    // MMCv3 card
                    // send generic intialization
                    self.card_type.set(SDCardType::MMC);
                    self.state.set(SpiState::InitRepeatGenericInit);
                    self.send_command(SDCmd::CMD1_Init, 0x0, write_buffer, read_buffer, 10);
                }
            }

            SpiState::InitRepeatAppSpecificInit => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    // card initialized
                    // set blocksize to 512
                    self.alarm_count.set(0);
                    self.state.set(SpiState::InitSetBlocksize);
                    self.send_command(
                        SDCmd::CMD16_SetBlockSize,
                        512,
                        write_buffer,
                        read_buffer,
                        10,
                    );
                } else if r1 == INITIALIZING_STATUS {
                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // try again after 10 ms
                    self.alarm_state.set(AlarmState::RepeatAppSpecificInit);
                    let interval = (10 as u32) * <A::Frequency>::frequency() / 1000;
                    let tics = self.alarm.now().wrapping_add(interval);
                    self.alarm.set_alarm(tics);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::InitializationFailure as u32);
                    });
                }
            }

            SpiState::InitRepeatGenericInit => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    // card initialized
                    // set blocksize to 512
                    self.alarm_count.set(0);
                    self.state.set(SpiState::InitSetBlocksize);
                    self.send_command(
                        SDCmd::CMD16_SetBlockSize,
                        512,
                        write_buffer,
                        read_buffer,
                        10,
                    );
                } else if r1 == INITIALIZING_STATUS {
                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // try again after 10 ms
                    self.alarm_state.set(AlarmState::RepeatGenericInit);
                    let interval = (10 as u32) * <A::Frequency>::frequency() / 1000;
                    let tics = self.alarm.now().wrapping_add(interval);
                    self.alarm.set_alarm(tics);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::InitializationFailure as u32);
                    });
                }
            }

            SpiState::InitSetBlocksize => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    // Read CSD register
                    // Note that the receive length needs to be increased here
                    //  to capture the 16-byte register (plus some slack)
                    self.state.set(SpiState::InitComplete);
                    self.send_command(SDCmd::CMD9_ReadCSD, 0x0, write_buffer, read_buffer, 28);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::InitializationFailure as u32);
                    });
                }
            }

            SpiState::InitComplete => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    let mut total_size: u64 = 0;

                    // find CSD register value
                    // Slide through 12-byte windows searching for beginning of
                    // the CSD register
                    for buf in read_buffer.windows(12) {
                        if buf[0] == DATA_TOKEN {
                            // get total size from CSD
                            if (buf[1] & 0xC0) == 0x00 {
                                // CSD version 1.0
                                let c_size = (((buf[7] & 0x03) as u32) << 10)
                                    | (((buf[8] & 0xFF) as u32) << 2)
                                    | (((buf[9] & 0xC0) as u32) >> 6);
                                let c_size_mult = (((buf[10] & 0x03) as u32) << 1)
                                    | (((buf[11] & 0x80) as u32) >> 7);
                                let read_bl_len = (buf[6] & 0x0F) as u32;

                                let block_count = (c_size + 1) * (1 << (c_size_mult + 2));
                                let block_len = 1 << read_bl_len;
                                total_size = block_count as u64 * block_len as u64;
                            } else {
                                // CSD version 2.0
                                let c_size = (((buf[8] & 0x3F) as u32) << 16)
                                    | (((buf[9] & 0xFF) as u32) << 8)
                                    | ((buf[10] & 0xFF) as u32);
                                total_size = ((c_size as u64) + 1) * 512 * 1024;
                            }

                            break;
                        }
                    }

                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // initialization complete
                    self.state.set(SpiState::Idle);
                    self.is_initialized.set(true);

                    // perform callback
                    self.client.get().map(move |client| {
                        client.init_done(512, total_size);
                    });
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::InitializationFailure as u32);
                    });
                }
            }

            SpiState::StartReadBlocks { count } => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    if count <= 1 {
                        // check for data block to be ready
                        self.state.set(SpiState::WaitReadBlock);
                        self.read_bytes(write_buffer, read_buffer, 1);
                    } else {
                        // check for data block to be ready
                        self.state.set(SpiState::WaitReadBlocks { count: count });
                        self.read_bytes(write_buffer, read_buffer, 1);
                    }
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::ReadFailure as u32);
                    });
                }
            }

            SpiState::WaitReadBlock => {
                if read_buffer[0] == DATA_TOKEN {
                    // data ready to read. Read block plus CRC
                    self.alarm_count.set(0);
                    self.state.set(SpiState::ReadBlockComplete);
                    self.read_bytes(write_buffer, read_buffer, 512 + 2);
                } else if read_buffer[0] == 0xFF {
                    // line is idling high, data is not ready

                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // try again after 1 ms
                    self.alarm_state.set(AlarmState::WaitForDataBlock);
                    let interval = (1 as u32) * <A::Frequency>::frequency() / 1000;
                    let tics = self.alarm.now().wrapping_add(interval);
                    self.alarm.set_alarm(tics);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::ReadFailure as u32);
                    });
                }
            }

            SpiState::ReadBlockComplete => {
                // replace buffers
                self.txbuffer.replace(write_buffer);
                self.rxbuffer.replace(read_buffer);

                // read finished, perform callback
                self.state.set(SpiState::Idle);
                self.rxbuffer.map(|read_buffer| {
                    self.client_buffer.take().map(move |buffer| {
                        // copy data to user buffer
                        // Limit to minimum length between buffer, read_buffer,
                        // and 512 (block size)
                        for (client_byte, &read_byte) in
                            buffer.iter_mut().zip(read_buffer.iter()).take(512)
                        {
                            *client_byte = read_byte;
                        }

                        // callback
                        let read_len = cmp::min(read_buffer.len(), cmp::min(buffer.len(), 512));
                        self.client.get().map(move |client| {
                            client.read_done(buffer, read_len);
                        });
                    });
                });
            }

            SpiState::WaitReadBlocks { count } => {
                if read_buffer[0] == DATA_TOKEN {
                    // data ready to read. Read block plus CRC
                    self.alarm_count.set(0);
                    self.state.set(SpiState::ReceivedBlock { count: count });
                    self.read_bytes(write_buffer, read_buffer, 512 + 2);
                } else if read_buffer[0] == 0xFF {
                    // line is idling high, data is not ready

                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // try again after 1 ms
                    self.alarm_state
                        .set(AlarmState::WaitForDataBlocks { count: count });
                    let interval = (1 as u32) * <A::Frequency>::frequency() / 1000;
                    let tics = self.alarm.now().wrapping_add(interval);
                    self.alarm.set_alarm(tics);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::ReadFailure as u32);
                    });
                }
            }

            SpiState::ReceivedBlock { count } => {
                // copy block over to client buffer
                self.client_buffer.map(|buffer| {
                    // copy block into client buffer
                    // Limit to minimum length between buffer, read_buffer, and
                    // 512 (block size)
                    let offset = self.client_offset.get();
                    for (client_byte, &read_byte) in buffer
                        .iter_mut()
                        .skip(offset)
                        .zip(read_buffer.iter())
                        .take(512)
                    {
                        *client_byte = read_byte;
                    }

                    // update offset
                    let read_len = cmp::min(read_buffer.len(), cmp::min(buffer.len(), 512));
                    self.client_offset.set(offset + read_len);
                });

                if count <= 1 {
                    // all blocks received. Terminate multiple read
                    self.state.set(SpiState::ReadBlocksComplete);
                    self.send_command(SDCmd::CMD12_StopRead, 0x0, write_buffer, read_buffer, 10);
                } else {
                    // check for next data block to be ready
                    self.state
                        .set(SpiState::WaitReadBlocks { count: count - 1 });
                    self.read_bytes(write_buffer, read_buffer, 1);
                }
            }

            SpiState::ReadBlocksComplete => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);

                    // read finished, perform callback
                    self.client_buffer.take().map(move |buffer| {
                        self.client.get().map(move |client| {
                            client.read_done(buffer, self.client_offset.get());
                        });
                    });
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::ReadFailure as u32);
                    });
                }
            }

            SpiState::StartWriteBlocks { count } => {
                // check response
                let (r1, _, _) = self.get_response(SDResponse::R1_Status, read_buffer);

                if r1 == SUCCESS_STATUS {
                    if count <= 1 {
                        let bytes_written = self.client_buffer.map_or(0, |buffer| {
                            // copy over data from client buffer
                            // Limit to minimum length between write_buffer,
                            // buffer, and 512 (block size)
                            for (write_byte, &client_byte) in
                                write_buffer.iter_mut().skip(1).zip(buffer.iter()).take(512)
                            {
                                *write_byte = client_byte;
                            }

                            // calculate number of bytes written
                            cmp::min(write_buffer.len(), cmp::min(buffer.len(), 512))
                        });

                        // set a known value for remaining bytes
                        for write_byte in write_buffer
                            .iter_mut()
                            .skip(1)
                            .skip(bytes_written)
                            .take(512)
                        {
                            *write_byte = 0xFF;
                        }

                        // set up remainder of data packet
                        write_buffer[0] = DATA_TOKEN; // Data token
                        write_buffer[513] = 0xFF; // dummy CRC
                        write_buffer[514] = 0xFF; // dummy CRC

                        // write data packet
                        self.state.set(SpiState::WriteBlockResponse);
                        self.write_bytes(write_buffer, read_buffer, 515);
                    } else {
                        // multi-block SD card writes are unimplemented
                        // This should have returned an error already, but if
                        // we got here somehow, return an error and quit now
                        self.txbuffer.replace(write_buffer);
                        self.rxbuffer.replace(read_buffer);
                        self.state.set(SpiState::Idle);
                        self.alarm_state.set(AlarmState::Idle);
                        self.alarm_count.set(0);
                        self.client.get().map(move |client| {
                            client.error(ErrorCode::WriteFailure as u32);
                        });
                    }
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::WriteFailure as u32);
                    });
                }
            }

            SpiState::WriteBlockResponse => {
                // Get data packet
                self.state.set(SpiState::WriteBlockBusy);
                self.read_bytes(write_buffer, read_buffer, 1);
            }

            SpiState::WriteBlockBusy => {
                if (read_buffer[0] & 0x1F) == 0x05 {
                    // check if sd card is busy
                    self.state.set(SpiState::WaitWriteBlockBusy);
                    self.read_bytes(write_buffer, read_buffer, 1);
                } else {
                    // error, send callback and quit
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);
                    self.state.set(SpiState::Idle);
                    self.alarm_state.set(AlarmState::Idle);
                    self.alarm_count.set(0);
                    self.client.get().map(move |client| {
                        client.error(ErrorCode::WriteFailure as u32);
                    });
                }
            }

            SpiState::WaitWriteBlockBusy => {
                // check if line is still held low (busy state)
                if read_buffer[0] != 0x00 {
                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // read finished, perform callback
                    self.state.set(SpiState::Idle);
                    self.alarm_count.set(0);
                    self.client_buffer.take().map(move |buffer| {
                        self.client.get().map(move |client| {
                            client.write_done(buffer);
                        });
                    });
                } else {
                    // replace buffers
                    self.txbuffer.replace(write_buffer);
                    self.rxbuffer.replace(read_buffer);

                    // try again after 1 ms
                    self.alarm_state.set(AlarmState::WaitForWriteBusy);
                    let interval = (1 as u32) * <A::Frequency>::frequency() / 1000;
                    let tics = self.alarm.now().wrapping_add(interval);
                    self.alarm.set_alarm(tics);
                }
            }

            SpiState::Idle => {
                // receiving an event from Idle means something was killed

                // replace buffers
                self.txbuffer.replace(write_buffer);
                self.rxbuffer.replace(read_buffer);
            }
        }
    }

    /// updates SD card state upon timer alarm fired
    fn process_alarm_states(&self) {
        // keep track of how many times the alarm has been called in a row
        let repeats = self.alarm_count.get();
        if repeats > 100 {
            // error, send callback and quit
            self.state.set(SpiState::Idle);
            self.alarm_state.set(AlarmState::Idle);
            self.alarm_count.set(0);
            self.client.get().map(move |client| {
                client.error(ErrorCode::TimeoutFailure as u32);
            });
        } else {
            self.alarm_count.set(repeats + 1);
        }

        match self.alarm_state.get() {
            AlarmState::DetectionChange => {
                // perform callback
                self.client.get().map(move |client| {
                    client.card_detection_changed(self.is_installed());
                });

                // re-enable interrupts
                self.detect_changes();
                self.alarm_count.set(0);
                self.alarm_state.set(AlarmState::Idle);
            }

            AlarmState::RepeatHCSInit => {
                // check card initialization again
                self.txbuffer.take().map(|write_buffer| {
                    self.rxbuffer.take().map(move |read_buffer| {
                        // send application-specific initialization in high capcity mode (HCS)
                        self.state.set(SpiState::SendManufSpecificCmd {
                            cmd: SDCmd::ACMD41_ManufSpecificInit,
                            arg: 0x40000000,
                        });
                        self.after_state.set(SpiState::InitRepeatHCSInit);
                        self.send_command(
                            SDCmd::CMD55_ManufSpecificCommand,
                            0x0,
                            write_buffer,
                            read_buffer,
                            10,
                        );
                    });
                });

                self.alarm_state.set(AlarmState::Idle);
            }

            AlarmState::RepeatAppSpecificInit => {
                // check card initialization again
                self.txbuffer.take().map(|write_buffer| {
                    self.rxbuffer.take().map(move |read_buffer| {
                        // send application-specific initialization
                        self.state.set(SpiState::SendManufSpecificCmd {
                            cmd: SDCmd::ACMD41_ManufSpecificInit,
                            arg: 0x0,
                        });
                        self.after_state.set(SpiState::InitRepeatAppSpecificInit);
                        self.send_command(
                            SDCmd::CMD55_ManufSpecificCommand,
                            0x0,
                            write_buffer,
                            read_buffer,
                            10,
                        );
                    });
                });

                self.alarm_state.set(AlarmState::Idle);
            }

            AlarmState::RepeatGenericInit => {
                // check card initialization again
                self.txbuffer.take().map(|write_buffer| {
                    self.rxbuffer.take().map(move |read_buffer| {
                        // send generic initialization
                        self.state.set(SpiState::InitRepeatGenericInit);
                        self.send_command(SDCmd::CMD1_Init, 0x0, write_buffer, read_buffer, 10);
                    });
                });

                self.alarm_state.set(AlarmState::Idle);
            }

            AlarmState::WaitForDataBlock => {
                // check card initialization again
                self.txbuffer.take().map(|write_buffer| {
                    self.rxbuffer.take().map(move |read_buffer| {
                        // wait until ready and then read data block, then done
                        self.state.set(SpiState::WaitReadBlock);
                        self.read_bytes(write_buffer, read_buffer, 1);
                    });
                });

                self.alarm_state.set(AlarmState::Idle);
            }

            AlarmState::WaitForDataBlocks { count } => {
                // check card initialization again
                self.txbuffer.take().map(|write_buffer| {
                    self.rxbuffer.take().map(move |read_buffer| {
                        // wait until ready and then read data block, then done
                        self.state.set(SpiState::WaitReadBlocks { count: count });
                        self.read_bytes(write_buffer, read_buffer, 1);
                    });
                });

                self.alarm_state.set(AlarmState::Idle);
            }

            AlarmState::WaitForWriteBusy => {
                // check card initialization again
                self.txbuffer.take().map(|write_buffer| {
                    self.rxbuffer.take().map(move |read_buffer| {
                        // check if sd card is busy
                        self.state.set(SpiState::WaitWriteBlockBusy);
                        self.read_bytes(write_buffer, read_buffer, 1);
                    });
                });

                self.alarm_state.set(AlarmState::Idle);
            }

            AlarmState::Idle => {
                // receiving an event from Idle means something was killed
                // do nothing
            }
        }
    }

    pub fn set_client<C: SDCardClient>(&self, client: &'static C) {
        self.client.set(Some(client));
    }

    pub fn is_installed(&self) -> bool {
        // if there is no detect pin, assume an sd card is installed
        self.detect_pin.get().map_or(true, |pin| {
            // sd card detection pin is active low
            pin.read() == false
        })
    }

    pub fn is_initialized(&self) -> bool {
        self.is_initialized.get()
    }

    /// watches SD card detect pin for changes, sends callback on change
    pub fn detect_changes(&self) {
        self.detect_pin.get().map(|pin| {
            pin.enable_interrupt(0, hil::gpio::InterruptMode::EitherEdge);
        });
    }

    pub fn initialize(&self) -> ReturnCode {
        // if not already, set card to uninitialized again
        self.is_initialized.set(false);

        // no point in initializing if the card is not installed
        if self.is_installed() {
            // reset the SD card in order to start initializing it
            self.txbuffer.take().map_or(ReturnCode::ENOMEM, |txbuffer| {
                self.rxbuffer
                    .take()
                    .map_or(ReturnCode::ENOMEM, move |rxbuffer| {
                        self.state.set(SpiState::InitReset);
                        self.send_command(SDCmd::CMD0_Reset, 0x0, txbuffer, rxbuffer, 10);

                        // command started successfully
                        ReturnCode::SUCCESS
                    })
            })
        } else {
            // no sd card installed
            ReturnCode::EUNINSTALLED
        }
    }

    pub fn read_blocks(&self, buffer: &'static mut [u8], sector: u32, count: u32) -> ReturnCode {
        // only if initialized and installed
        if self.is_installed() {
            if self.is_initialized() {
                self.txbuffer.take().map_or(ReturnCode::ENOMEM, |txbuffer| {
                    self.rxbuffer
                        .take()
                        .map_or(ReturnCode::ENOMEM, move |rxbuffer| {
                            // save the user buffer for later
                            self.client_buffer.replace(buffer);
                            self.client_offset.set(0);

                            // convert block address to byte address for non-block
                            //  access cards
                            let mut address = sector;
                            if self.card_type.get() != SDCardType::SDv2BlockAddressable {
                                address *= 512;
                            }

                            self.state.set(SpiState::StartReadBlocks { count: count });
                            if count == 1 {
                                self.send_command(
                                    SDCmd::CMD17_ReadSingle,
                                    address,
                                    txbuffer,
                                    rxbuffer,
                                    10,
                                );
                            } else {
                                self.send_command(
                                    SDCmd::CMD18_ReadMultiple,
                                    address,
                                    txbuffer,
                                    rxbuffer,
                                    10,
                                );
                            }

                            // command started successfully
                            ReturnCode::SUCCESS
                        })
                })
            } else {
                // sd card not initialized
                ReturnCode::ERESERVE
            }
        } else {
            // sd card not installed
            ReturnCode::EUNINSTALLED
        }
    }

    pub fn write_blocks(&self, buffer: &'static mut [u8], sector: u32, count: u32) -> ReturnCode {
        // only if initialized and installed
        if self.is_installed() {
            if self.is_initialized() {
                self.txbuffer.take().map_or(ReturnCode::ENOMEM, |txbuffer| {
                    self.rxbuffer
                        .take()
                        .map_or(ReturnCode::ENOMEM, move |rxbuffer| {
                            // save the user buffer for later
                            self.client_buffer.replace(buffer);
                            self.client_offset.set(0);

                            // convert block address to byte address for non-block
                            //  access cards
                            let mut address = sector;
                            if self.card_type.get() != SDCardType::SDv2BlockAddressable {
                                address *= 512;
                            }

                            self.state.set(SpiState::StartWriteBlocks { count: count });
                            if count == 1 {
                                self.send_command(
                                    SDCmd::CMD24_WriteSingle,
                                    address,
                                    txbuffer,
                                    rxbuffer,
                                    10,
                                );

                                // command started successfully
                                ReturnCode::SUCCESS
                            } else {
                                // can't write multiple blocks yet
                                ReturnCode::ENOSUPPORT
                            }
                        })
                })
            } else {
                // sd card not initialized
                ReturnCode::ERESERVE
            }
        } else {
            // sd card not installed
            ReturnCode::EUNINSTALLED
        }
    }
}

/// Handle callbacks from the SPI peripheral
impl<'a, A: hil::time::Alarm + 'a> hil::spi::SpiMasterClient for SDCard<'a, A> {
    fn read_write_done(
        &self,
        mut write_buffer: &'static mut [u8],
        read_buffer: Option<&'static mut [u8]>,
        len: usize,
    ) {
        // unrwap so we don't have to deal with options everywhere
        read_buffer.map(move |read_buffer| {
            self.process_spi_states(write_buffer, read_buffer, len);
        });
    }
}

/// Handle callbacks from the timer
impl<'a, A: hil::time::Alarm + 'a> hil::time::Client for SDCard<'a, A> {
    fn fired(&self) {
        self.process_alarm_states();
    }
}

/// Handle callbacks from the card detection pin
impl<'a, A: hil::time::Alarm + 'a> hil::gpio::Client for SDCard<'a, A> {
    fn fired(&self, _: usize) {
        // check if there was an open transaction with the sd card
        if self.alarm_state.get() != AlarmState::Idle || self.state.get() != SpiState::Idle {
            // something was running when this occurred. Kill the transaction and
            //  send an error callback
            self.state.set(SpiState::Idle);
            self.alarm_state.set(AlarmState::Idle);
            self.client.get().map(move |client| {
                client.error(ErrorCode::CardStateChanged as u32);
            });
        }

        // either the card is new or gone, in either case it isn't initialized
        self.is_initialized.set(false);

        // disable additional interrupts
        self.detect_pin.get().map(|pin| {
            pin.disable_interrupt();
        });

        // run a timer for 500 ms in order to let the sd card settle
        self.alarm_state.set(AlarmState::DetectionChange);
        let interval = (500 as u32) * <A::Frequency>::frequency() / 1000;
        let tics = self.alarm.now().wrapping_add(interval);
        self.alarm.set_alarm(tics);
    }
}

/// Application driver for SD Card capsule, layers on top of SD Card capsule
/// This is used if the SDCard is going to be attached directly to userspace
/// syscalls. SDCardDriver can be ignored if another capsule is going to build
/// off of the SDCard instead
pub struct SDCardDriver<'a, A: hil::time::Alarm + 'a> {
    sdcard: &'a SDCard<'a, A>,
    app: MapCell<App>,
    kernel_buf: TakeCell<'static, [u8]>,
}

/// Holds buffers and whatnot that the application has passed us.
struct App {
    callback: Option<Callback>,
    write_buffer: Option<AppSlice<Shared, u8>>,
    read_buffer: Option<AppSlice<Shared, u8>>,
}

impl Default for App {
    fn default() -> App {
        App {
            callback: None,
            write_buffer: None,
            read_buffer: None,
        }
    }
}

/// Buffer for SD card driver, assigned in board `main.rs` files
pub static mut KERNEL_BUFFER: [u8; 512] = [0; 512];

/// Functions for SDCardDriver
impl<'a, A: hil::time::Alarm + 'a> SDCardDriver<'a, A> {
    /// Create new SD card userland interface
    ///
    /// sdcard - SDCard interface to provide application access to
    /// kernel_buf - buffer used to hold SD card blocks, must be at least 512
    ///     bytes in length
    pub fn new(
        sdcard: &'a SDCard<'a, A>,
        kernel_buf: &'static mut [u8; 512],
    ) -> SDCardDriver<'a, A> {
        // return new SDCardDriver
        SDCardDriver {
            sdcard: sdcard,
            app: MapCell::new(App::default()),
            kernel_buf: TakeCell::new(kernel_buf),
        }
    }
}

/// Handle callbacks from SDCard
impl<'a, A: hil::time::Alarm + 'a> SDCardClient for SDCardDriver<'a, A> {
    fn card_detection_changed(&self, installed: bool) {
        self.app.map(|app| {
            app.callback.map(|mut cb| {
                cb.schedule(0, installed as usize, 0);
            });
        });
    }

    fn init_done(&self, block_size: u32, total_size: u64) {
        self.app.map(|app| {
            app.callback.map(|mut cb| {
                let size_in_kb = ((total_size >> 10) & 0xFFFFFFFF) as usize;
                cb.schedule(1, block_size as usize, size_in_kb);
            });
        });
    }

    fn read_done(&self, data: &'static mut [u8], len: usize) {
        self.kernel_buf.replace(data);
        self.app.map(|app| {
            let mut read_len: usize = 0;
            self.kernel_buf.map(|data| {
                app.read_buffer.as_mut().map(move |read_buffer| {
                    // copy bytes to user buffer
                    // Limit to minimum length between read_buffer, data, and
                    // len field
                    for (read_byte, &data_byte) in read_buffer.iter_mut().zip(data.iter()).take(len)
                    {
                        *read_byte = data_byte;
                    }
                    read_len = cmp::min(read_buffer.len(), cmp::min(data.len(), len));
                });
            });

            // perform callback
            // Note that we are explicitly performing the callback even if no
            // data was read or if the app's read_buffer doesn't exist
            app.callback.map(|mut cb| {
                cb.schedule(2, read_len, 0);
            });
        });
    }

    fn write_done(&self, buffer: &'static mut [u8]) {
        self.kernel_buf.replace(buffer);

        self.app.map(|app| {
            app.callback.map(|mut cb| {
                cb.schedule(3, 0, 0);
            });
        });
    }

    fn error(&self, error: u32) {
        self.app.map(|app| {
            app.callback.map(|mut cb| {
                cb.schedule(4, error as usize, 0);
            });
        });
    }
}

/// Connections to userspace syscalls
impl<'a, A: hil::time::Alarm + 'a> Driver for SDCardDriver<'a, A> {
    fn allow(&self, _appid: AppId, allow_num: usize, slice: AppSlice<Shared, u8>) -> ReturnCode {
        match allow_num {
            // Pass read buffer in from application
            0 => {
                self.app.map(|app| app.read_buffer = Some(slice));
                ReturnCode::SUCCESS
            }

            // Pass write buffer in from application
            1 => {
                self.app.map(|app| app.write_buffer = Some(slice));
                ReturnCode::SUCCESS
            }

            _ => ReturnCode::ENOSUPPORT,
        }
    }

    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> ReturnCode {
        match subscribe_num {
            // Set callback
            0 => {
                self.app.map(|app| app.callback = Some(callback));
                ReturnCode::SUCCESS
            }

            _ => ReturnCode::ENOSUPPORT,
        }
    }

    fn command(&self, command_num: usize, data: usize, _: usize, _: AppId) -> ReturnCode {
        match command_num {
            // check if present
            0 => ReturnCode::SUCCESS,

            // is_installed
            1 => {
                let value = self.sdcard.is_installed() as usize;
                ReturnCode::SuccessWithValue { value: value }
            }

            // initialize
            2 => self.sdcard.initialize(),

            // read_block
            3 => self.kernel_buf
                .take()
                .map_or(ReturnCode::EBUSY, |kernel_buf| {
                    self.sdcard.read_blocks(kernel_buf, data as u32, 1)
                }),

            // write_block
            4 => {
                self.app.map_or(ReturnCode::ENOMEM, |app| {
                    app.write_buffer
                        .as_mut()
                        .map_or(ReturnCode::ENOMEM, |write_buffer| {
                            self.kernel_buf
                                .take()
                                .map_or(ReturnCode::EBUSY, |kernel_buf| {
                                    // copy over write data from application
                                    // Limit to minimum length between kernel_buf,
                                    // write_buffer, and 512 (block size)
                                    for (kernel_byte, &write_byte) in
                                        kernel_buf.iter_mut().zip(write_buffer.iter()).take(512)
                                    {
                                        *kernel_byte = write_byte;
                                    }

                                    // begin writing
                                    self.sdcard.write_blocks(kernel_buf, data as u32, 1)
                                })
                        })
                })
            }

            _ => ReturnCode::ENOSUPPORT,
        }
    }
}