1 // Copyright (C) 2016 Michael McMaster <michael@codesrc.com>
3 // This file is part of SCSI2SD.
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.
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.
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/>.
19 #include "usbd_msc_storage_sd.h"
22 #include "stm32f2xx.h"
26 #include "stm32f4xx.h"
29 #include "../bsp_driver_sd.h"
34 #include "../config.h"
35 #include "../geometry.h"
36 #include "../inquiry.h"
37 #include "usb_device.h"
39 uint8_t NoSDInquiryData[36] =
46 0x1F, // Standard length
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 */
56 static int8_t s2s_usbd_storage_Init(uint8_t lun);
58 static int8_t s2s_usbd_storage_GetCapacity(
61 uint16_t *block_size);
63 static int8_t s2s_usbd_storage_IsReady(uint8_t lun);
65 static int8_t s2s_usbd_storage_IsWriteProtected(uint8_t lun);
67 int8_t s2s_usbd_storage_Read(
73 int8_t s2s_usbd_storage_Write(
79 int8_t s2s_usbd_storage_GetMaxLun (void);
80 uint32_t s2s_usbd_storage_Inquiry (uint8_t lun, uint8_t* buf, uint8_t maxlen);
83 USBD_StorageTypeDef USBD_MSC_SD_fops =
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
95 static const S2S_TargetCfg* getUsbConfig(uint8_t lun) {
97 for (int i = 0; i < S2S_MAX_TARGETS; ++i)
99 const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
100 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
112 return s2s_getConfigByIndex(0); // Fallback, try not to crash
115 int8_t s2s_usbd_storage_Init(uint8_t lun)
120 int8_t s2s_usbd_storage_GetCapacity (uint8_t lun, uint32_t *block_num, uint16_t *block_size)
122 const S2S_TargetCfg* cfg = getUsbConfig(lun);
124 if (cfg->scsiId & S2S_CFG_TARGET_ENABLED)
126 uint32_t capacity = getScsiCapacity(
131 *block_num = capacity;
132 *block_size = cfg->bytesPerSector;
133 return capacity ? 0 : 1;
143 uint32_t s2s_usbd_storage_Inquiry (uint8_t lun, uint8_t* buf, uint8_t maxlen)
145 const S2S_TargetCfg* cfg = getUsbConfig(lun);
146 if (cfg->scsiId & S2S_CFG_TARGET_ENABLED)
148 return s2s_getStandardInquiry(cfg, buf, maxlen);
152 memcpy(buf, NoSDInquiryData, maxlen < sizeof(NoSDInquiryData) ? maxlen : sizeof(NoSDInquiryData));
153 return sizeof(NoSDInquiryData);
157 int8_t s2s_usbd_storage_IsReady (uint8_t lun)
159 const S2S_TargetCfg* cfg = getUsbConfig(lun);
162 (cfg->scsiId & S2S_CFG_TARGET_ENABLED) &&
163 (blockDev.state & DISK_PRESENT) &&
164 (blockDev.state & DISK_INITIALISED)
165 ) ? 0 : 1; // inverse logic
169 int8_t s2s_usbd_storage_IsWriteProtected (uint8_t lun)
171 return blockDev.state & DISK_WP;
174 int8_t s2s_usbd_storage_Read (uint8_t lun,
180 const S2S_TargetCfg* cfg = getUsbConfig(lun);
182 if (cfg->bytesPerSector == 512)
184 BSP_SD_ReadBlocks_DMA(
186 cfg->sdSectorStart + blk_addr,
191 int sdPerScsi = SDSectorsPerSCSISector(cfg->bytesPerSector);
192 int sdSectorNum = cfg->sdSectorStart + (blk_addr * sdPerScsi);
194 for (int blk = 0; blk < blk_len; ++blk)
196 for (int i = 0; i < SDSectorsPerSCSISector(cfg->bytesPerSector); ++i)
198 uint8_t partial[512] S2S_DMA_ALIGN;
199 BSP_SD_ReadBlocks_DMA(
205 int validBytes = cfg->bytesPerSector % SD_SECTOR_SIZE;
206 if (validBytes == 0) validBytes = SD_SECTOR_SIZE;
208 memcpy(buf, partial, validBytes);
220 int8_t s2s_usbd_storage_Write (uint8_t lun,
226 const S2S_TargetCfg* cfg = getUsbConfig(lun);
228 if (cfg->bytesPerSector == 512)
230 BSP_SD_WriteBlocks_DMA(
232 cfg->sdSectorStart + blk_addr,
237 int sdPerScsi = SDSectorsPerSCSISector(cfg->bytesPerSector);
238 int sdSectorNum = cfg->sdSectorStart + (blk_addr * sdPerScsi);
240 for (int blk = 0; blk < blk_len; ++blk)
242 for (int i = 0; i < SDSectorsPerSCSISector(cfg->bytesPerSector); ++i)
244 uint8_t partial[512] S2S_DMA_ALIGN;
245 memcpy(partial, buf, 512);
247 BSP_SD_WriteBlocks_DMA(
253 int validBytes = cfg->bytesPerSector % SD_SECTOR_SIZE;
254 if (validBytes == 0) validBytes = SD_SECTOR_SIZE;
267 int8_t s2s_usbd_storage_GetMaxLun (void)
270 for (int i = 0; i < S2S_MAX_TARGETS; ++i)
272 const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
273 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
278 return count - 1 < 0 ? 0 : count - 1;
281 void s2s_initUsbDeviceStorage(void)
284 USBD_MSC_RegisterStorage(&hUsbDeviceFS, &USBD_MSC_SD_fops);
287 USBD_MSC_RegisterStorage(&hUsbDeviceHS, &USBD_MSC_SD_fops);