2d59bab5eee003992e22655ea0c4469edb2936ac
[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 * 512ll, 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 \r
96 static void sdInitDMA()\r
97 {\r
98         // One-time init only.\r
99         static uint8_t init = 0;\r
100         if (init == 0)\r
101         {\r
102                 init = 1;\r
103 \r
104                 //TODO MM SEE STUPID SD_DMA_RxCplt that require the SD IRQs to preempt\r
105                 // Ie. priority must be geater than the SDIO_IRQn priority.\r
106                 // 4 bits preemption, NO sub priority.\r
107                 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);\r
108                 HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 8, 0);\r
109                 HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);\r
110                 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);\r
111                 HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 8, 0);\r
112                 HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);\r
113         }\r
114 }\r
115 \r
116 static void sdClear()\r
117 {\r
118         sdDev.version = 0;\r
119         sdDev.capacity = 0;\r
120         memset(sdDev.csd, 0, sizeof(sdDev.csd));\r
121         memset(sdDev.cid, 0, sizeof(sdDev.cid));\r
122 }\r
123 \r
124 static int sdDoInit()\r
125 {\r
126         int result = 0;\r
127 \r
128         sdClear();\r
129 \r
130         int8_t error = BSP_SD_Init();\r
131         if (error == MSD_OK)\r
132         {\r
133                 HAL_SD_CardInfoTypeDef cardInfo;\r
134                 HAL_SD_GetCardInfo(&hsd, &cardInfo);\r
135                 memcpy(sdDev.csd, hsd.CSD, sizeof(sdDev.csd));\r
136                 memcpy(sdDev.cid, hsd.CID, sizeof(sdDev.cid));\r
137                 sdDev.capacity = cardInfo.BlockNbr;\r
138                 blockDev.state |= DISK_PRESENT | DISK_INITIALISED;\r
139                 result = 1;\r
140 \r
141                 goto out;\r
142         }\r
143 \r
144 //bad:\r
145         blockDev.state &= ~(DISK_PRESENT | DISK_INITIALISED);\r
146 \r
147         sdDev.capacity = 0;\r
148 \r
149 out:\r
150         s2s_ledOff();\r
151         return result;\r
152 }\r
153 \r
154 int sdInit()\r
155 {\r
156         // Check if there's an SD card present.\r
157         int result = 0;\r
158 \r
159         static int firstInit = 1;\r
160 \r
161         if (firstInit)\r
162         {\r
163                 blockDev.state &= ~(DISK_PRESENT | DISK_INITIALISED);\r
164                 sdClear();\r
165                 sdInitDMA();\r
166         }\r
167 \r
168         if (firstInit || (scsiDev.phase == BUS_FREE))\r
169         {\r
170                 uint8_t cs = HAL_GPIO_ReadPin(nSD_CD_GPIO_Port, nSD_CD_Pin) ? 0 : 1;\r
171                 uint8_t wp = HAL_GPIO_ReadPin(nSD_WP_GPIO_Port, nSD_WP_Pin) ? 0 : 1;\r
172 \r
173                 if (cs && !(blockDev.state & DISK_PRESENT))\r
174                 {\r
175                         s2s_ledOn();\r
176 \r
177                         // Debounce\r
178                         if (!firstInit)\r
179                         {\r
180                                 s2s_delay_ms(250);\r
181                         }\r
182 \r
183                         if (sdDoInit())\r
184                         {\r
185                                 blockDev.state |= DISK_PRESENT | DISK_INITIALISED;\r
186 \r
187                                 if (wp)\r
188                                 {\r
189                                         blockDev.state |= DISK_WP;\r
190                                 }\r
191                                 else\r
192                                 {\r
193                                         blockDev.state &= ~DISK_WP;\r
194                                 }\r
195 \r
196                                 // Always "start" the device. Many systems (eg. Apple System 7)\r
197                                 // won't respond properly to\r
198                                 // LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED sense\r
199                                 // code, even if they stopped it first with\r
200                                 // START STOP UNIT command.\r
201                                 blockDev.state |= DISK_STARTED;\r
202 \r
203                                 result = 1;\r
204 \r
205                                 s2s_ledOff();\r
206                         }\r
207                         else\r
208                         {\r
209                                 for (int i = 0; i < 10; ++i)\r
210                                 {\r
211                                         // visual indicator of SD error\r
212                                         s2s_ledOff();\r
213                                         s2s_delay_ms(50);\r
214                                         s2s_ledOn();\r
215                                         s2s_delay_ms(50);\r
216                                 }\r
217                                 s2s_ledOff();\r
218                         }\r
219                 }\r
220                 else if (!cs && (blockDev.state & DISK_PRESENT))\r
221                 {\r
222                         sdDev.capacity = 0;\r
223                         blockDev.state &= ~DISK_PRESENT;\r
224                         blockDev.state &= ~DISK_INITIALISED;\r
225                         int i;\r
226                         for (i = 0; i < S2S_MAX_TARGETS; ++i)\r
227                         {\r
228                                 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;\r
229                         }\r
230 \r
231                         HAL_SD_DeInit(&hsd);\r
232                 }\r
233         }\r
234         firstInit = 0;\r
235 \r
236         return result;\r
237 }\r
238 \r