Slight write speed improvement
[SCSI2SD-V6.git] / src / firmware / usb_device / usbd_msc_storage_sd.c
1 //      Copyright (C) 2016 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
19 #include "usbd_msc_storage_sd.h"
20
21 #ifdef STM32F2xx
22 #include "stm32f2xx.h"
23 #endif
24
25 #ifdef STM32F4xx
26 #include "stm32f4xx.h"
27 #endif
28
29 #include "../bsp_driver_sd.h"
30 #include "../bsp.h"
31 #include "../disk.h"
32 #include "../led.h"
33 #include "../sd.h"
34 #include "../config.h"
35 #include "../geometry.h"
36 #include "../inquiry.h"
37 #include "usb_device.h"
38
39 uint8_t NoSDInquiryData[] =  /* 36 */
40 {
41   /* LUN 0 */
42   0x00,
43   0x80, // Removable
44   0x02,
45   0x02,
46   0x1F, // Standard length
47   0x00,
48   0x00,
49   0x00,
50   'C', 'O', 'D', 'E', 'S', 'R', 'C', ' ', /* Manufacturer : 8 bytes */
51   'S', 'C', 'S', 'I', '2', 'S', 'D', ' ', /* Product      : 16 Bytes */
52   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
53   '6', '.', 'X', 'X',                     /* Version      : 4 Bytes */
54 };
55
56 static int8_t s2s_usbd_storage_Init(uint8_t lun);
57
58 static int8_t s2s_usbd_storage_GetCapacity(
59         uint8_t lun,
60         uint32_t *block_num,
61         uint16_t *block_size);
62
63 static int8_t s2s_usbd_storage_IsReady(uint8_t lun);
64
65 static int8_t s2s_usbd_storage_IsWriteProtected(uint8_t lun);
66
67 int8_t s2s_usbd_storage_Read(
68         uint8_t lun,
69         uint8_t *buf,
70         uint32_t blk_addr,
71         uint16_t blk_len);
72
73 int8_t s2s_usbd_storage_Write(
74         uint8_t lun,
75         uint8_t *buf,
76         uint32_t blk_addr,
77         uint16_t blk_len);
78
79 int8_t s2s_usbd_storage_GetMaxLun (void);
80 uint32_t s2s_usbd_storage_Inquiry (uint8_t lun, uint8_t* buf, uint8_t maxlen);
81
82
83 USBD_StorageTypeDef USBD_MSC_SD_fops =
84 {
85         s2s_usbd_storage_Init,
86         s2s_usbd_storage_GetCapacity,
87         s2s_usbd_storage_IsReady,
88         s2s_usbd_storage_IsWriteProtected,
89         s2s_usbd_storage_Read,
90         s2s_usbd_storage_Write,
91         s2s_usbd_storage_GetMaxLun,
92         s2s_usbd_storage_Inquiry
93 };
94
95 static const S2S_TargetCfg* getUsbConfig(uint8_t lun) {
96         int count = 0;
97         for (int i = 0; i < S2S_MAX_TARGETS; ++i)
98         {
99                 const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
100                 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
101                 {
102                         if (count == lun)
103                         {
104                                 return cfg;
105                         }
106                         else
107                         {
108                                 count++;
109                         }
110                 }
111         }
112         return s2s_getConfigByIndex(0); // Fallback, try not to crash
113 }
114
115 int8_t s2s_usbd_storage_Init(uint8_t lun)
116 {
117         return (0);
118 }
119
120 int8_t s2s_usbd_storage_GetCapacity (uint8_t lun, uint32_t *block_num, uint16_t *block_size)
121 {
122         const S2S_TargetCfg* cfg = getUsbConfig(lun);
123
124     if (cfg->scsiId & S2S_CFG_TARGET_ENABLED)
125     {
126         uint32_t capacity = getScsiCapacity(
127             cfg->sdSectorStart,
128             cfg->bytesPerSector,
129             cfg->scsiSectors);
130
131         *block_num  = capacity;
132         *block_size = cfg->bytesPerSector;
133         return capacity ? 0 : 1;
134     }
135     else
136     {
137         *block_num = 0;
138         *block_size = 512;
139         return 1;
140     }
141 }
142
143 uint32_t s2s_usbd_storage_Inquiry (uint8_t lun, uint8_t* buf, uint8_t maxlen)
144 {
145         const S2S_TargetCfg* cfg = getUsbConfig(lun);
146     if (cfg->scsiId & S2S_CFG_TARGET_ENABLED)
147     {
148         return s2s_getStandardInquiry(cfg, buf, maxlen);
149     }
150     else
151     {
152         memcpy(buf, NoSDInquiryData, maxlen < sizeof(NoSDInquiryData) ? maxlen : sizeof(NoSDInquiryData));
153         return sizeof(NoSDInquiryData);
154     }
155 }
156
157 int8_t s2s_usbd_storage_IsReady (uint8_t lun)
158 {
159     const S2S_TargetCfg* cfg = getUsbConfig(lun);
160     return (
161             cfg &&
162             (cfg->scsiId & S2S_CFG_TARGET_ENABLED) &&
163             (blockDev.state & DISK_PRESENT) &&
164             (blockDev.state & DISK_INITIALISED)
165             ) ? 0 : 1; // inverse logic
166 }
167
168
169 int8_t s2s_usbd_storage_IsWriteProtected (uint8_t lun)
170 {
171         return blockDev.state & DISK_WP;
172 }
173
174 int8_t s2s_usbd_storage_Read (uint8_t lun,
175                 uint8_t *buf,
176                 uint32_t blk_addr,
177                 uint16_t blk_len)
178 {
179         s2s_ledOn();
180         const S2S_TargetCfg* cfg = getUsbConfig(lun);
181
182         if (cfg->bytesPerSector == 512)
183         {
184                 BSP_SD_ReadBlocks_DMA(
185                         buf,
186                         cfg->sdSectorStart + blk_addr,
187                         blk_len);
188         }
189         else
190         {
191                 int sdPerScsi = SDSectorsPerSCSISector(cfg->bytesPerSector);
192                 int sdSectorNum =  cfg->sdSectorStart + (blk_addr * sdPerScsi);
193
194                 for (int blk = 0; blk < blk_len; ++blk)
195                 {
196                         for (int i = 0; i < SDSectorsPerSCSISector(cfg->bytesPerSector); ++i)
197                         {
198                                 uint8_t partial[512] S2S_DMA_ALIGN;
199                                 BSP_SD_ReadBlocks_DMA(
200                                         partial,
201                                         sdSectorNum,
202                                         1);
203                                 sdSectorNum++;
204
205                                 int validBytes = cfg->bytesPerSector % SD_SECTOR_SIZE;
206                                 if (validBytes == 0) validBytes = SD_SECTOR_SIZE;
207
208                                 memcpy(buf, partial, validBytes);
209
210                                 buf += validBytes;
211                         }
212
213                 }
214
215         }
216         s2s_ledOff();
217         return 0;
218 }
219
220 int8_t s2s_usbd_storage_Write (uint8_t lun,
221                 uint8_t *buf,
222                 uint32_t blk_addr,
223                 uint16_t blk_len)
224 {
225         s2s_ledOn();
226         const S2S_TargetCfg* cfg = getUsbConfig(lun);
227
228         if (cfg->bytesPerSector == 512)
229         {
230                 BSP_SD_WriteBlocks_DMA(
231                         buf,
232                         cfg->sdSectorStart + blk_addr,
233                         blk_len);
234         }
235         else
236         {
237                 int sdPerScsi = SDSectorsPerSCSISector(cfg->bytesPerSector);
238                 int sdSectorNum =  cfg->sdSectorStart + (blk_addr * sdPerScsi);
239
240                 for (int blk = 0; blk < blk_len; ++blk)
241                 {
242                         for (int i = 0; i < SDSectorsPerSCSISector(cfg->bytesPerSector); ++i)
243                         {
244                                 uint8_t partial[512] S2S_DMA_ALIGN;
245                                 memcpy(partial, buf, 512);
246
247                                 BSP_SD_WriteBlocks_DMA(
248                                         partial,
249                                         sdSectorNum,
250                                         1);
251                                 sdSectorNum++;
252
253                                 int validBytes = cfg->bytesPerSector % SD_SECTOR_SIZE;
254                                 if (validBytes == 0) validBytes = SD_SECTOR_SIZE;
255
256                                 buf += validBytes;
257                         }
258
259                 }
260
261         }
262
263         s2s_ledOff();
264         return 0;
265 }
266
267 int8_t s2s_usbd_storage_GetMaxLun (void)
268 {
269         int count = 0;
270         for (int i = 0; i < S2S_MAX_TARGETS; ++i)
271         {
272                 const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
273                 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
274                 {
275                         count++;
276                 }
277         }
278         return count - 1 < 0 ? 0 : count - 1;
279 }
280
281 void s2s_initUsbDeviceStorage(void)
282 {
283 #ifdef S2S_USB_FS
284         USBD_MSC_RegisterStorage(&hUsbDeviceFS, &USBD_MSC_SD_fops);
285 #endif
286 #ifdef S2S_USB_HS
287         USBD_MSC_RegisterStorage(&hUsbDeviceHS, &USBD_MSC_SD_fops);
288 #endif
289 }
290