ZuluSCSI_platform_msc.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /**
  2. * Copyright (c) 2023-2024 zigzagjoe
  3. *
  4. * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
  5. *
  6. * https://www.gnu.org/licenses/gpl-3.0.html
  7. * ----
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version. 
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. * GNU General Public License for more details. 
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  20. **/
  21. #ifdef PLATFORM_MASS_STORAGE
  22. #include <SdFat.h>
  23. #include "ZuluSCSI_platform.h"
  24. #include "ZuluSCSI_log.h"
  25. #include "ZuluSCSI_msc.h"
  26. #include "ZuluSCSI_settings.h"
  27. #include "usb_serial.h"
  28. /* gd32 USB code is all C linked */
  29. extern "C" {
  30. #include <drv_usb_hw.h>
  31. #include <usbd_core.h>
  32. #include <drv_usbd_int.h>
  33. #include "usb_conf.h"
  34. #include "usbd_msc_core.h"
  35. #include "usbd_msc_mem.h"
  36. #include "usbd_msc_bbb.h"
  37. }
  38. /* local function prototypes ('static') */
  39. static int8_t storageInit(uint8_t Lun);
  40. static int8_t storageIsReady(uint8_t Lun);
  41. static int8_t storageIsWriteProtected(uint8_t Lun);
  42. static int8_t storageGetMaxLun(void);
  43. static int8_t storageRead(uint8_t Lun,
  44. uint8_t *buf,
  45. uint32_t BlkAddr,
  46. uint16_t BlkLen);
  47. static int8_t storageWrite(uint8_t Lun,
  48. uint8_t *buf,
  49. uint32_t BlkAddr,
  50. uint16_t BlkLen);
  51. usbd_mem_cb USBD_SD_fops = {
  52. .mem_init = storageInit,
  53. .mem_ready = storageIsReady,
  54. .mem_protected = storageIsWriteProtected,
  55. .mem_read = storageRead,
  56. .mem_write = storageWrite,
  57. .mem_maxlun = storageGetMaxLun,
  58. .mem_inquiry_data = {(uint8_t *)storageInquiryData},
  59. .mem_block_size = {SD_SECTOR_SIZE},
  60. .mem_block_len = {0}
  61. };
  62. usbd_mem_cb *usbd_mem_fops = &USBD_SD_fops;
  63. // shared with usb serial
  64. extern usb_core_driver cdc_acm;
  65. // external global SD variable
  66. extern SdFs SD;
  67. // private globals
  68. static bool unitReady = false;
  69. /* returns true if card reader mode should be entered. sd card is available. */
  70. bool platform_sense_msc() {
  71. // kill usb serial.
  72. usbd_disconnect (&cdc_acm);
  73. // set the MSC storage size
  74. usbd_mem_fops->mem_block_len[0] = SD.card()->sectorCount();
  75. unitReady = true;
  76. // init the MSC class, uses ISR and other global routines from usb_serial.cpp
  77. usbd_init(&cdc_acm, USB_CORE_ENUM_HS, &msc_desc, &msc_class);
  78. logmsg("Waiting for USB enumeration to expose SD card as a mass storage device");
  79. // wait for up to a second to be begin to be enumerated
  80. uint32_t start = millis();
  81. while ((uint32_t)(millis() - start) < CR_ENUM_TIMEOUT)
  82. if (cdc_acm.dev.cur_status >= USBD_ADDRESSED)
  83. return true;
  84. //if not, disconnect MSC class...
  85. usbd_disconnect (&cdc_acm);
  86. // and bring serial back for later.
  87. usb_serial_init();
  88. return false;
  89. }
  90. /* perform MSC-specific init tasks */
  91. void platform_enter_msc() {
  92. dbgmsg("USB MSC buffer size: ", (uint32_t) MSC_MEDIA_PACKET_SIZE);
  93. // give the host a moment to finish enumerate and "load" media
  94. uint32_t start = millis();
  95. while ((USBD_CONFIGURED != cdc_acm.dev.cur_status) && ((uint32_t)(millis() - start) < CR_ENUM_TIMEOUT) )
  96. delay(100);
  97. }
  98. /* return true while remaining in msc mode, and perform periodic tasks */
  99. bool platform_run_msc() {
  100. usbd_msc_handler *msc = (usbd_msc_handler *)cdc_acm.dev.class_data[USBD_MSC_INTERFACE];
  101. // stupid windows doesn't send start_stop_unit events if it is ejected via safely remove devices.
  102. // it just stops talking to the device so we don't know we've been ejected....
  103. // other OSes always send the start_stop_unit, windows does too when ejected from explorer.
  104. // so we watch for the OS suspending device and assume we're done in USB mode if so.
  105. // this will also trigger if the host were to suspend usb device due to going to sleep
  106. // however, I hope no sane OS would sleep mid transfer or with a dirty filesystem.
  107. // Note: Mac OS X apparently not sane.
  108. uint8_t is_suspended = cdc_acm.dev.cur_status == (uint8_t)USBD_SUSPENDED;
  109. return (! msc->scsi_disk_pop) && !is_suspended;
  110. }
  111. void platform_exit_msc() {
  112. unitReady = false;
  113. // disconnect msc....
  114. usbd_disconnect (&cdc_acm);
  115. // catch our breath....
  116. delay(200);
  117. // ... and bring usb serial up
  118. usb_serial_init();
  119. }
  120. /*!
  121. \brief initialize the storage medium
  122. \param[in] Lun: logical unit number
  123. \param[out] none
  124. \retval status
  125. */
  126. static int8_t storageInit(uint8_t Lun)
  127. {
  128. return 0;
  129. }
  130. /*!
  131. \brief check whether the medium is ready
  132. \param[in] Lun: logical unit number
  133. \param[out] none
  134. \retval status
  135. */
  136. static int8_t storageIsReady(uint8_t Lun)
  137. {
  138. return ! unitReady; // 0 = success / unit is ready
  139. }
  140. /*!
  141. \brief check whether the medium is write-protected
  142. \param[in] Lun: logical unit number
  143. \param[out] none
  144. \retval status
  145. */
  146. static int8_t storageIsWriteProtected(uint8_t Lun)
  147. {
  148. return ! unitReady; // 0 = read/write
  149. }
  150. /*!
  151. \brief read data from the medium
  152. \param[in] Lun: logical unit number
  153. \param[in] buf: pointer to the buffer to save data
  154. \param[in] BlkAddr: address of 1st block to be read
  155. \param[in] BlkLen: number of blocks to be read
  156. \param[out] none
  157. \retval status
  158. */
  159. static int8_t storageRead(uint8_t Lun,
  160. uint8_t *buf,
  161. uint32_t BlkAddr,
  162. uint16_t BlkLen)
  163. {
  164. // divide by sector size to convert address to LBA
  165. bool rc = SD.card()->readSectors(BlkAddr/SD_SECTOR_SIZE, buf, BlkLen);
  166. // only blink fast on reads; writes will override this
  167. if (MSC_LEDMode == LED_SOLIDON)
  168. MSC_LEDMode = LED_BLINK_FAST;
  169. return !rc;
  170. }
  171. /*!
  172. \brief write data to the medium
  173. \param[in] Lun: logical unit number
  174. \param[in] buf: pointer to the buffer to write
  175. \param[in] BlkAddr: address of 1st block to be written
  176. \param[in] BlkLen: number of blocks to be write
  177. \param[out] none
  178. \retval status
  179. */
  180. static int8_t storageWrite(uint8_t Lun,
  181. uint8_t *buf,
  182. uint32_t BlkAddr,
  183. uint16_t BlkLen)
  184. {
  185. // divide by sector size to convert address to LBA
  186. bool rc = SD.card()->writeSectors(BlkAddr/SD_SECTOR_SIZE, buf, BlkLen);
  187. // always slow blink
  188. MSC_LEDMode = LED_BLINK_SLOW;
  189. return !rc;
  190. }
  191. /*!
  192. \brief get number of supported logical unit
  193. \param[in] none
  194. \param[out] none
  195. \retval number of logical unit
  196. */
  197. static int8_t storageGetMaxLun(void)
  198. {
  199. return 0; // number of LUNs supported - 1
  200. }
  201. #endif // PLATFORM_MASS_STORAGE