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