Fix DMA IRQ priorty to be less than the SDIO IRQ
[SCSI2SD-V6.git] / src / firmware / sd.c
1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
2 //
3 // This file is part of SCSI2SD.
4 //
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
17
18 #ifdef STM32F2xx
19 #include "stm32f2xx.h"
20 #endif
21
22 #ifdef STM32F4xx
23 #include "stm32f4xx.h"
24 #endif
25
26 #include "sdio.h"
27 #include "bsp_driver_sd.h"
28
29
30 #include "scsi.h"
31 #include "config.h"
32 #include "disk.h"
33 #include "sd.h"
34 #include "led.h"
35 #include "time.h"
36
37 #include "scsiPhy.h"
38
39 #include <string.h>
40
41 // Global
42 SdDevice sdDev;
43
44 static int sdCmdActive = 0;
45
46 int
47 sdReadDMAPoll(uint32_t remainingSectors)
48 {
49 // TODO DMA byte counting disabled for now as it's not
50 // working.
51 // We can ask the SDIO controller how many bytes have been
52 // processed (SDIO_GetDataCounter()) but I'm not sure if that
53 // means the data has been transfered via dma to memory yet.
54 // uint32_t dmaBytesRemaining = __HAL_DMA_GET_COUNTER(hsd.hdmarx) * 4;
55
56 if (HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY)
57 {
58 // DMA transfer is complete
59 sdCmdActive = 0;
60 return remainingSectors;
61 }
62 /* else
63 {
64 return remainingSectors - ((dmaBytesRemaining + (SD_SECTOR_SIZE - 1)) / SD_SECTOR_SIZE);
65 }*/
66 return 0;
67 }
68
69 void sdReadDMA(uint32_t lba, uint32_t sectors, uint8_t* outputBuffer)
70 {
71 if (HAL_SD_ReadBlocks_DMA(&hsd, outputBuffer, lba * 512ll, sectors) != HAL_OK)
72 {
73 scsiDiskReset();
74
75 scsiDev.status = CHECK_CONDITION;
76 scsiDev.target->sense.code = HARDWARE_ERROR;
77 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;
78 scsiDev.phase = STATUS;
79 }
80 else
81 {
82 sdCmdActive = 1;
83 }
84 }
85
86 void sdCompleteTransfer()
87 {
88 if (sdCmdActive)
89 {
90 HAL_SD_Abort(&hsd);
91 sdCmdActive = 0;
92 }
93 }
94
95 static void sdClear()
96 {
97 sdDev.version = 0;
98 sdDev.capacity = 0;
99 memset(sdDev.csd, 0, sizeof(sdDev.csd));
100 memset(sdDev.cid, 0, sizeof(sdDev.cid));
101 }
102
103 static int sdDoInit()
104 {
105 int result = 0;
106
107 sdClear();
108
109 int8_t error = BSP_SD_Init();
110 if (error == MSD_OK)
111 {
112 HAL_SD_CardInfoTypeDef cardInfo;
113 HAL_SD_GetCardInfo(&hsd, &cardInfo);
114 memcpy(sdDev.csd, hsd.CSD, sizeof(sdDev.csd));
115 memcpy(sdDev.cid, hsd.CID, sizeof(sdDev.cid));
116 sdDev.capacity = cardInfo.BlockNbr;
117 blockDev.state |= DISK_PRESENT | DISK_INITIALISED;
118 result = 1;
119
120 goto out;
121 }
122
123 //bad:
124 blockDev.state &= ~(DISK_PRESENT | DISK_INITIALISED);
125
126 sdDev.capacity = 0;
127
128 out:
129 s2s_ledOff();
130 return result;
131 }
132
133 int sdInit()
134 {
135 // Check if there's an SD card present.
136 int result = 0;
137
138 static int firstInit = 1;
139
140 if (firstInit)
141 {
142 blockDev.state &= ~(DISK_PRESENT | DISK_INITIALISED);
143 sdClear();
144 }
145
146 if (firstInit || (scsiDev.phase == BUS_FREE))
147 {
148 uint8_t cs = HAL_GPIO_ReadPin(nSD_CD_GPIO_Port, nSD_CD_Pin) ? 0 : 1;
149 uint8_t wp = HAL_GPIO_ReadPin(nSD_WP_GPIO_Port, nSD_WP_Pin) ? 0 : 1;
150
151 if (cs && !(blockDev.state & DISK_PRESENT))
152 {
153 s2s_ledOn();
154
155 // Debounce
156 if (!firstInit)
157 {
158 s2s_delay_ms(250);
159 }
160
161 if (sdDoInit())
162 {
163 blockDev.state |= DISK_PRESENT | DISK_INITIALISED;
164
165 if (wp)
166 {
167 blockDev.state |= DISK_WP;
168 }
169 else
170 {
171 blockDev.state &= ~DISK_WP;
172 }
173
174 // Always "start" the device. Many systems (eg. Apple System 7)
175 // won't respond properly to
176 // LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED sense
177 // code, even if they stopped it first with
178 // START STOP UNIT command.
179 blockDev.state |= DISK_STARTED;
180
181 result = 1;
182
183 s2s_ledOff();
184 }
185 else
186 {
187 for (int i = 0; i < 10; ++i)
188 {
189 // visual indicator of SD error
190 s2s_ledOff();
191 s2s_delay_ms(50);
192 s2s_ledOn();
193 s2s_delay_ms(50);
194 }
195 s2s_ledOff();
196 }
197 }
198 else if (!cs && (blockDev.state & DISK_PRESENT))
199 {
200 sdDev.capacity = 0;
201 blockDev.state &= ~DISK_PRESENT;
202 blockDev.state &= ~DISK_INITIALISED;
203 int i;
204 for (i = 0; i < S2S_MAX_TARGETS; ++i)
205 {
206 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
207 }
208
209 HAL_SD_DeInit(&hsd);
210 }
211 }
212 firstInit = 0;
213
214 return result;
215 }
216