My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

udi_msc.c 29KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /**
  2. * \file
  3. *
  4. * \brief USB Device Mass Storage Class (MSC) interface.
  5. *
  6. * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
  7. *
  8. * \asf_license_start
  9. *
  10. * \page License
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions are met:
  14. *
  15. * 1. Redistributions of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. *
  18. * 2. Redistributions in binary form must reproduce the above copyright notice,
  19. * this list of conditions and the following disclaimer in the documentation
  20. * and/or other materials provided with the distribution.
  21. *
  22. * 3. The name of Atmel may not be used to endorse or promote products derived
  23. * from this software without specific prior written permission.
  24. *
  25. * 4. This software may only be redistributed and used in connection with an
  26. * Atmel microcontroller product.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
  29. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  30. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  31. * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
  32. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  36. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  37. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * \asf_license_stop
  41. *
  42. */
  43. /*
  44. * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
  45. */
  46. #ifdef ARDUINO_ARCH_SAM
  47. #include "conf_usb.h"
  48. #include "usb_protocol.h"
  49. #include "usb_protocol_msc.h"
  50. #include "spc_protocol.h"
  51. #include "sbc_protocol.h"
  52. #include "udd.h"
  53. #include "udc.h"
  54. #include "udi_msc.h"
  55. #include "ctrl_access.h"
  56. #include <string.h>
  57. #if ENABLED(SDSUPPORT)
  58. #ifndef UDI_MSC_NOTIFY_TRANS_EXT
  59. # define UDI_MSC_NOTIFY_TRANS_EXT()
  60. #endif
  61. /**
  62. * \ingroup udi_msc_group
  63. * \defgroup udi_msc_group_udc Interface with USB Device Core (UDC)
  64. *
  65. * Structures and functions required by UDC.
  66. *
  67. * @{
  68. */
  69. bool udi_msc_enable(void);
  70. void udi_msc_disable(void);
  71. bool udi_msc_setup(void);
  72. uint8_t udi_msc_getsetting(void);
  73. //! Global structure which contains standard UDI API for UDC
  74. UDC_DESC_STORAGE udi_api_t udi_api_msc = {
  75. .enable = udi_msc_enable,
  76. .disable = udi_msc_disable,
  77. .setup = udi_msc_setup,
  78. .getsetting = udi_msc_getsetting,
  79. .sof_notify = NULL,
  80. };
  81. //@}
  82. /**
  83. * \ingroup udi_msc_group
  84. * \defgroup udi_msc_group_internal Implementation of UDI MSC
  85. *
  86. * Class internal implementation
  87. * @{
  88. */
  89. //! Static block size for all memories
  90. #define UDI_MSC_BLOCK_SIZE 512L
  91. /**
  92. * \name Variables to manage SCSI requests
  93. */
  94. //@{
  95. //! Structure to receive a CBW packet
  96. UDC_BSS(4) static struct usb_msc_cbw udi_msc_cbw;
  97. //! Structure to send a CSW packet
  98. UDC_DATA(4) static struct usb_msc_csw udi_msc_csw =
  99. {.dCSWSignature = CPU_TO_BE32(USB_CSW_SIGNATURE) };
  100. //! Number of lun
  101. UDC_DATA(4) static uint8_t udi_msc_nb_lun = 0;
  102. //! Structure with current SCSI sense data
  103. UDC_BSS(4) static struct scsi_request_sense_data udi_msc_sense;
  104. /**
  105. * \name Variables to manage the background read/write SCSI commands
  106. */
  107. //@{
  108. //! True if an invalid CBW command has been detected
  109. static bool udi_msc_b_cbw_invalid = false;
  110. //! True if a transfer command must be processed
  111. static bool udi_msc_b_trans_req = false;
  112. //! True if it is a read command, else write command
  113. static bool udi_msc_b_read;
  114. //! Memory address to execute the command
  115. static uint32_t udi_msc_addr;
  116. //! Number of block to transfer
  117. static uint16_t udi_msc_nb_block;
  118. //! Signal end of transfer, if true
  119. volatile bool udi_msc_b_ack_trans = true;
  120. //! Status of transfer, aborted if true
  121. volatile bool udi_msc_b_abort_trans;
  122. //! Signal (re)init of transfer, if true (by reset/reconnect)
  123. volatile bool udi_msc_b_reset_trans = true;
  124. //@}
  125. //@}
  126. /**
  127. * \name Internal routines
  128. */
  129. //@{
  130. /**
  131. * \name Routines to process CBW packet
  132. */
  133. //@{
  134. /**
  135. * \brief Stall CBW request
  136. */
  137. static void udi_msc_cbw_invalid(void);
  138. /**
  139. * \brief Stall CSW request
  140. */
  141. static void udi_msc_csw_invalid(void);
  142. /**
  143. * \brief Links a callback and buffer on endpoint OUT reception
  144. *
  145. * Called by:
  146. * - enable interface
  147. * - at the end of previous command after sending the CSW
  148. */
  149. static void udi_msc_cbw_wait(void);
  150. /**
  151. * \brief Callback called after CBW reception
  152. * Called by UDD when a transfer is finished or aborted
  153. *
  154. * \param status UDD_EP_TRANSFER_OK, if transfer is finished
  155. * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted
  156. * \param nb_received number of data transfered
  157. */
  158. static void udi_msc_cbw_received(udd_ep_status_t status,
  159. iram_size_t nb_received, udd_ep_id_t ep);
  160. /**
  161. * \brief Function to check the CBW length and direction
  162. * Call it after SCSI command decode to check integrity of command
  163. *
  164. * \param alloc_len number of bytes that device want transfer
  165. * \param dir_flag Direction of transfer (USB_CBW_DIRECTION_IN/OUT)
  166. *
  167. * \retval true if the command can be processed
  168. */
  169. static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag);
  170. //@}
  171. /**
  172. * \name Routines to process small data packet
  173. */
  174. //@{
  175. /**
  176. * \brief Sends data on MSC IN endpoint
  177. * Called by SCSI command which must send a data to host followed by a CSW
  178. *
  179. * \param buffer Internal RAM buffer to send
  180. * \param buf_size Size of buffer to send
  181. */
  182. static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size);
  183. /**
  184. * \brief Callback called after data sent
  185. * It start CSW packet process
  186. *
  187. * \param status UDD_EP_TRANSFER_OK, if transfer finish
  188. * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
  189. * \param nb_sent number of data transfered
  190. */
  191. static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent,
  192. udd_ep_id_t ep);
  193. //@}
  194. /**
  195. * \name Routines to process CSW packet
  196. */
  197. //@{
  198. /**
  199. * \brief Build CSW packet and send it
  200. *
  201. * Called at the end of SCSI command
  202. */
  203. static void udi_msc_csw_process(void);
  204. /**
  205. * \brief Sends CSW
  206. *
  207. * Called by #udi_msc_csw_process()
  208. * or UDD callback when endpoint halt is cleared
  209. */
  210. void udi_msc_csw_send(void);
  211. /**
  212. * \brief Callback called after CSW sent
  213. * It restart CBW reception.
  214. *
  215. * \param status UDD_EP_TRANSFER_OK, if transfer is finished
  216. * \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted
  217. * \param nb_sent number of data transfered
  218. */
  219. static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent,
  220. udd_ep_id_t ep);
  221. //@}
  222. /**
  223. * \name Routines manage sense data
  224. */
  225. //@{
  226. /**
  227. * \brief Reinitialize sense data.
  228. */
  229. static void udi_msc_clear_sense(void);
  230. /**
  231. * \brief Update sense data with new value to signal a fail
  232. *
  233. * \param sense_key Sense key
  234. * \param add_sense Additional Sense Code
  235. * \param lba LBA corresponding at error
  236. */
  237. static void udi_msc_sense_fail(uint8_t sense_key, uint16_t add_sense,
  238. uint32_t lba);
  239. /**
  240. * \brief Update sense data with new value to signal success
  241. */
  242. static void udi_msc_sense_pass(void);
  243. /**
  244. * \brief Update sense data to signal that memory is not present
  245. */
  246. static void udi_msc_sense_fail_not_present(void);
  247. /**
  248. * \brief Update sense data to signal that memory is busy
  249. */
  250. static void udi_msc_sense_fail_busy_or_change(void);
  251. /**
  252. * \brief Update sense data to signal a hardware error on memory
  253. */
  254. static void udi_msc_sense_fail_hardware(void);
  255. /**
  256. * \brief Update sense data to signal that memory is protected
  257. */
  258. static void udi_msc_sense_fail_protected(void);
  259. /**
  260. * \brief Update sense data to signal that CDB fields are not valid
  261. */
  262. static void udi_msc_sense_fail_cdb_invalid(void);
  263. /**
  264. * \brief Update sense data to signal that command is not supported
  265. */
  266. static void udi_msc_sense_command_invalid(void);
  267. //@}
  268. /**
  269. * \name Routines manage SCSI Commands
  270. */
  271. //@{
  272. /**
  273. * \brief Process SPC Request Sense command
  274. * Returns error information about last command
  275. */
  276. static void udi_msc_spc_requestsense(void);
  277. /**
  278. * \brief Process SPC Inquiry command
  279. * Returns information (name,version) about disk
  280. */
  281. static void udi_msc_spc_inquiry(void);
  282. /**
  283. * \brief Checks state of disk
  284. *
  285. * \retval true if disk is ready, otherwise false and updates sense data
  286. */
  287. static bool udi_msc_spc_testunitready_global(void);
  288. /**
  289. * \brief Process test unit ready command
  290. * Returns state of logical unit
  291. */
  292. static void udi_msc_spc_testunitready(void);
  293. /**
  294. * \brief Process prevent allow medium removal command
  295. */
  296. static void udi_msc_spc_prevent_allow_medium_removal(void);
  297. /**
  298. * \brief Process mode sense command
  299. *
  300. * \param b_sense10 Sense10 SCSI command, if true
  301. * \param b_sense10 Sense6 SCSI command, if false
  302. */
  303. static void udi_msc_spc_mode_sense(bool b_sense10);
  304. /**
  305. * \brief Process start stop command
  306. */
  307. static void udi_msc_sbc_start_stop(void);
  308. /**
  309. * \brief Process read capacity command
  310. */
  311. static void udi_msc_sbc_read_capacity(void);
  312. /**
  313. * \brief Process read10 or write10 command
  314. *
  315. * \param b_read Read transfer, if true,
  316. * \param b_read Write transfer, if false
  317. */
  318. static void udi_msc_sbc_trans(bool b_read);
  319. //@}
  320. //@}
  321. bool udi_msc_enable(void)
  322. {
  323. uint8_t lun;
  324. udi_msc_b_trans_req = false;
  325. udi_msc_b_cbw_invalid = false;
  326. udi_msc_b_ack_trans = true;
  327. udi_msc_b_reset_trans = true;
  328. udi_msc_nb_lun = get_nb_lun();
  329. if (0 == udi_msc_nb_lun)
  330. return false; // No lun available, then not authorize to enable interface
  331. udi_msc_nb_lun--;
  332. // Call application callback
  333. // to initialize memories or signal that interface is enabled
  334. if (!UDI_MSC_ENABLE_EXT())
  335. return false;
  336. // Load the medium on each LUN
  337. for (lun = 0; lun <= udi_msc_nb_lun; lun ++) {
  338. mem_unload(lun, false);
  339. }
  340. // Start MSC process by CBW reception
  341. udi_msc_cbw_wait();
  342. return true;
  343. }
  344. void udi_msc_disable(void)
  345. {
  346. udi_msc_b_trans_req = false;
  347. udi_msc_b_ack_trans = true;
  348. udi_msc_b_reset_trans = true;
  349. UDI_MSC_DISABLE_EXT();
  350. }
  351. bool udi_msc_setup(void)
  352. {
  353. if (Udd_setup_is_in()) {
  354. // Requests Interface GET
  355. if (Udd_setup_type() == USB_REQ_TYPE_CLASS) {
  356. // Requests Class Interface Get
  357. switch (udd_g_ctrlreq.req.bRequest) {
  358. case USB_REQ_MSC_GET_MAX_LUN:
  359. // Give the number of memories available
  360. if (1 != udd_g_ctrlreq.req.wLength)
  361. return false; // Error for USB host
  362. if (0 != udd_g_ctrlreq.req.wValue)
  363. return false;
  364. udd_g_ctrlreq.payload = &udi_msc_nb_lun;
  365. udd_g_ctrlreq.payload_size = 1;
  366. return true;
  367. }
  368. }
  369. }
  370. if (Udd_setup_is_out()) {
  371. // Requests Interface SET
  372. if (Udd_setup_type() == USB_REQ_TYPE_CLASS) {
  373. // Requests Class Interface Set
  374. switch (udd_g_ctrlreq.req.bRequest) {
  375. case USB_REQ_MSC_BULK_RESET:
  376. // Reset MSC interface
  377. if (0 != udd_g_ctrlreq.req.wLength)
  378. return false;
  379. if (0 != udd_g_ctrlreq.req.wValue)
  380. return false;
  381. udi_msc_b_cbw_invalid = false;
  382. udi_msc_b_trans_req = false;
  383. // Abort all tasks (transfer or clear stall wait) on endpoints
  384. udd_ep_abort(UDI_MSC_EP_OUT);
  385. udd_ep_abort(UDI_MSC_EP_IN);
  386. // Restart by CBW wait
  387. udi_msc_cbw_wait();
  388. return true;
  389. }
  390. }
  391. }
  392. return false; // Not supported request
  393. }
  394. uint8_t udi_msc_getsetting(void)
  395. {
  396. return 0; // MSC don't have multiple alternate setting
  397. }
  398. // ------------------------
  399. //------- Routines to process CBW packet
  400. static void udi_msc_cbw_invalid(void)
  401. {
  402. if (!udi_msc_b_cbw_invalid)
  403. return; // Don't re-stall endpoint if error reseted by setup
  404. udd_ep_set_halt(UDI_MSC_EP_OUT);
  405. // If stall cleared then re-stall it. Only Setup MSC Reset can clear it
  406. udd_ep_wait_stall_clear(UDI_MSC_EP_OUT, udi_msc_cbw_invalid);
  407. }
  408. static void udi_msc_csw_invalid(void)
  409. {
  410. if (!udi_msc_b_cbw_invalid)
  411. return; // Don't re-stall endpoint if error reseted by setup
  412. udd_ep_set_halt(UDI_MSC_EP_IN);
  413. // If stall cleared then re-stall it. Only Setup MSC Reset can clear it
  414. udd_ep_wait_stall_clear(UDI_MSC_EP_IN, udi_msc_csw_invalid);
  415. }
  416. static void udi_msc_cbw_wait(void)
  417. {
  418. // Register buffer and callback on OUT endpoint
  419. if (!udd_ep_run(UDI_MSC_EP_OUT, true,
  420. (uint8_t *) & udi_msc_cbw,
  421. sizeof(udi_msc_cbw),
  422. udi_msc_cbw_received)) {
  423. // OUT endpoint not available (halted), then wait a clear of halt.
  424. udd_ep_wait_stall_clear(UDI_MSC_EP_OUT, udi_msc_cbw_wait);
  425. }
  426. }
  427. static void udi_msc_cbw_received(udd_ep_status_t status,
  428. iram_size_t nb_received, udd_ep_id_t ep)
  429. {
  430. UNUSED(ep);
  431. // Check status of transfer
  432. if (UDD_EP_TRANSFER_OK != status) {
  433. // Transfer aborted
  434. // Now wait MSC setup reset to relaunch CBW reception
  435. return;
  436. }
  437. // Check CBW integrity:
  438. // transfer status/CBW length/CBW signature
  439. if ((sizeof(udi_msc_cbw) != nb_received)
  440. || (udi_msc_cbw.dCBWSignature !=
  441. CPU_TO_BE32(USB_CBW_SIGNATURE))) {
  442. // (5.2.1) Devices receiving a CBW with an invalid signature should stall
  443. // further traffic on the Bulk In pipe, and either stall further traffic
  444. // or accept and discard further traffic on the Bulk Out pipe, until
  445. // reset recovery.
  446. udi_msc_b_cbw_invalid = true;
  447. udi_msc_cbw_invalid();
  448. udi_msc_csw_invalid();
  449. return;
  450. }
  451. // Check LUN asked
  452. udi_msc_cbw.bCBWLUN &= USB_CBW_LUN_MASK;
  453. if (udi_msc_cbw.bCBWLUN > udi_msc_nb_lun) {
  454. // Bad LUN, then stop command process
  455. udi_msc_sense_fail_cdb_invalid();
  456. udi_msc_csw_process();
  457. return;
  458. }
  459. // Prepare CSW residue field with the size requested
  460. udi_msc_csw.dCSWDataResidue =
  461. le32_to_cpu(udi_msc_cbw.dCBWDataTransferLength);
  462. // Decode opcode
  463. switch (udi_msc_cbw.CDB[0]) {
  464. case SPC_REQUEST_SENSE:
  465. udi_msc_spc_requestsense();
  466. break;
  467. case SPC_INQUIRY:
  468. udi_msc_spc_inquiry();
  469. break;
  470. case SPC_MODE_SENSE6:
  471. udi_msc_spc_mode_sense(false);
  472. break;
  473. case SPC_MODE_SENSE10:
  474. udi_msc_spc_mode_sense(true);
  475. break;
  476. case SPC_TEST_UNIT_READY:
  477. udi_msc_spc_testunitready();
  478. break;
  479. case SBC_READ_CAPACITY10:
  480. udi_msc_sbc_read_capacity();
  481. break;
  482. case SBC_START_STOP_UNIT:
  483. udi_msc_sbc_start_stop();
  484. break;
  485. // Accepts request to support plug/plug in case of card reader
  486. case SPC_PREVENT_ALLOW_MEDIUM_REMOVAL:
  487. udi_msc_spc_prevent_allow_medium_removal();
  488. break;
  489. // Accepts request to support full format from Windows
  490. case SBC_VERIFY10:
  491. udi_msc_sense_pass();
  492. udi_msc_csw_process();
  493. break;
  494. case SBC_READ10:
  495. udi_msc_sbc_trans(true);
  496. break;
  497. case SBC_WRITE10:
  498. udi_msc_sbc_trans(false);
  499. break;
  500. default:
  501. udi_msc_sense_command_invalid();
  502. udi_msc_csw_process();
  503. break;
  504. }
  505. }
  506. static bool udi_msc_cbw_validate(uint32_t alloc_len, uint8_t dir_flag)
  507. {
  508. /*
  509. * The following cases should result in a phase error:
  510. * - Case 2: Hn < Di
  511. * - Case 3: Hn < Do
  512. * - Case 7: Hi < Di
  513. * - Case 8: Hi <> Do
  514. * - Case 10: Ho <> Di
  515. * - Case 13: Ho < Do
  516. */
  517. if (((udi_msc_cbw.bmCBWFlags ^ dir_flag) & USB_CBW_DIRECTION_IN)
  518. || (udi_msc_csw.dCSWDataResidue < alloc_len)) {
  519. udi_msc_sense_fail_cdb_invalid();
  520. udi_msc_csw_process();
  521. return false;
  522. }
  523. /*
  524. * The following cases should result in a stall and nonzero
  525. * residue:
  526. * - Case 4: Hi > Dn
  527. * - Case 5: Hi > Di
  528. * - Case 9: Ho > Dn
  529. * - Case 11: Ho > Do
  530. */
  531. return true;
  532. }
  533. // ------------------------
  534. //------- Routines to process small data packet
  535. static void udi_msc_data_send(uint8_t * buffer, uint8_t buf_size)
  536. {
  537. // Sends data on IN endpoint
  538. if (!udd_ep_run(UDI_MSC_EP_IN, true,
  539. buffer, buf_size, udi_msc_data_sent)) {
  540. // If endpoint not available, then exit process command
  541. udi_msc_sense_fail_hardware();
  542. udi_msc_csw_process();
  543. }
  544. }
  545. static void udi_msc_data_sent(udd_ep_status_t status, iram_size_t nb_sent,
  546. udd_ep_id_t ep)
  547. {
  548. UNUSED(ep);
  549. if (UDD_EP_TRANSFER_OK != status) {
  550. // Error protocol
  551. // Now wait MSC setup reset to relaunch CBW reception
  552. return;
  553. }
  554. // Update sense data
  555. udi_msc_sense_pass();
  556. // Update CSW
  557. udi_msc_csw.dCSWDataResidue -= nb_sent;
  558. udi_msc_csw_process();
  559. }
  560. // ------------------------
  561. //------- Routines to process CSW packet
  562. static void udi_msc_csw_process(void)
  563. {
  564. if (0 != udi_msc_csw.dCSWDataResidue) {
  565. // Residue not NULL
  566. // then STALL next request from USB host on corresponding endpoint
  567. if (udi_msc_cbw.bmCBWFlags & USB_CBW_DIRECTION_IN)
  568. udd_ep_set_halt(UDI_MSC_EP_IN);
  569. else
  570. udd_ep_set_halt(UDI_MSC_EP_OUT);
  571. }
  572. // Prepare and send CSW
  573. udi_msc_csw.dCSWTag = udi_msc_cbw.dCBWTag;
  574. udi_msc_csw.dCSWDataResidue = cpu_to_le32(udi_msc_csw.dCSWDataResidue);
  575. udi_msc_csw_send();
  576. }
  577. void udi_msc_csw_send(void)
  578. {
  579. // Sends CSW on IN endpoint
  580. if (!udd_ep_run(UDI_MSC_EP_IN, false,
  581. (uint8_t *) & udi_msc_csw,
  582. sizeof(udi_msc_csw),
  583. udi_msc_csw_sent)) {
  584. // Endpoint not available
  585. // then restart CSW sent when endpoint IN STALL will be cleared
  586. udd_ep_wait_stall_clear(UDI_MSC_EP_IN, udi_msc_csw_send);
  587. }
  588. }
  589. static void udi_msc_csw_sent(udd_ep_status_t status, iram_size_t nb_sent,
  590. udd_ep_id_t ep)
  591. {
  592. UNUSED(ep);
  593. UNUSED(status);
  594. UNUSED(nb_sent);
  595. // CSW is sent or not
  596. // In all case, restart process and wait CBW
  597. udi_msc_cbw_wait();
  598. }
  599. // ------------------------
  600. //------- Routines manage sense data
  601. static void udi_msc_clear_sense(void)
  602. {
  603. memset((uint8_t*)&udi_msc_sense, 0, sizeof(struct scsi_request_sense_data));
  604. udi_msc_sense.valid_reponse_code = SCSI_SENSE_VALID | SCSI_SENSE_CURRENT;
  605. udi_msc_sense.AddSenseLen = SCSI_SENSE_ADDL_LEN(sizeof(udi_msc_sense));
  606. }
  607. static void udi_msc_sense_fail(uint8_t sense_key, uint16_t add_sense,
  608. uint32_t lba)
  609. {
  610. udi_msc_clear_sense();
  611. udi_msc_csw.bCSWStatus = USB_CSW_STATUS_FAIL;
  612. udi_msc_sense.sense_flag_key = sense_key;
  613. udi_msc_sense.information[0] = lba >> 24;
  614. udi_msc_sense.information[1] = lba >> 16;
  615. udi_msc_sense.information[2] = lba >> 8;
  616. udi_msc_sense.information[3] = lba;
  617. udi_msc_sense.AddSenseCode = add_sense >> 8;
  618. udi_msc_sense.AddSnsCodeQlfr = add_sense;
  619. }
  620. static void udi_msc_sense_pass(void)
  621. {
  622. udi_msc_clear_sense();
  623. udi_msc_csw.bCSWStatus = USB_CSW_STATUS_PASS;
  624. }
  625. static void udi_msc_sense_fail_not_present(void)
  626. {
  627. udi_msc_sense_fail(SCSI_SK_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0);
  628. }
  629. static void udi_msc_sense_fail_busy_or_change(void)
  630. {
  631. udi_msc_sense_fail(SCSI_SK_UNIT_ATTENTION,
  632. SCSI_ASC_NOT_READY_TO_READY_CHANGE, 0);
  633. }
  634. static void udi_msc_sense_fail_hardware(void)
  635. {
  636. udi_msc_sense_fail(SCSI_SK_HARDWARE_ERROR,
  637. SCSI_ASC_NO_ADDITIONAL_SENSE_INFO, 0);
  638. }
  639. static void udi_msc_sense_fail_protected(void)
  640. {
  641. udi_msc_sense_fail(SCSI_SK_DATA_PROTECT, SCSI_ASC_WRITE_PROTECTED, 0);
  642. }
  643. static void udi_msc_sense_fail_cdb_invalid(void)
  644. {
  645. udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST,
  646. SCSI_ASC_INVALID_FIELD_IN_CDB, 0);
  647. }
  648. static void udi_msc_sense_command_invalid(void)
  649. {
  650. udi_msc_sense_fail(SCSI_SK_ILLEGAL_REQUEST,
  651. SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, 0);
  652. }
  653. // ------------------------
  654. //------- Routines manage SCSI Commands
  655. static void udi_msc_spc_requestsense(void)
  656. {
  657. uint8_t length = udi_msc_cbw.CDB[4];
  658. // Can't send more than sense data length
  659. if (length > sizeof(udi_msc_sense))
  660. length = sizeof(udi_msc_sense);
  661. if (!udi_msc_cbw_validate(length, USB_CBW_DIRECTION_IN))
  662. return;
  663. // Send sense data
  664. udi_msc_data_send((uint8_t*)&udi_msc_sense, length);
  665. }
  666. static void udi_msc_spc_inquiry(void)
  667. {
  668. uint8_t length, i;
  669. UDC_DATA(4)
  670. // Constant inquiry data for all LUNs
  671. static struct scsi_inquiry_data udi_msc_inquiry_data = {
  672. .pq_pdt = SCSI_INQ_PQ_CONNECTED | SCSI_INQ_DT_DIR_ACCESS,
  673. .version = SCSI_INQ_VER_SPC,
  674. .flags3 = SCSI_INQ_RSP_SPC2,
  675. .addl_len = SCSI_INQ_ADDL_LEN(sizeof(struct scsi_inquiry_data)),
  676. .vendor_id = {UDI_MSC_GLOBAL_VENDOR_ID},
  677. .product_rev = {UDI_MSC_GLOBAL_PRODUCT_VERSION},
  678. };
  679. length = udi_msc_cbw.CDB[4];
  680. // Can't send more than inquiry data length
  681. if (length > sizeof(udi_msc_inquiry_data))
  682. length = sizeof(udi_msc_inquiry_data);
  683. if (!udi_msc_cbw_validate(length, USB_CBW_DIRECTION_IN))
  684. return;
  685. if ((0 != (udi_msc_cbw.CDB[1] & (SCSI_INQ_REQ_EVPD | SCSI_INQ_REQ_CMDT)))
  686. || (0 != udi_msc_cbw.CDB[2])) {
  687. // CMDT and EPVD bits are not at 0
  688. // PAGE or OPERATION CODE fields are not empty
  689. // = No standard inquiry asked
  690. udi_msc_sense_fail_cdb_invalid(); // Command is unsupported
  691. udi_msc_csw_process();
  692. return;
  693. }
  694. udi_msc_inquiry_data.flags1 = mem_removal(udi_msc_cbw.bCBWLUN) ?
  695. SCSI_INQ_RMB : 0;
  696. //* Fill product ID field
  697. // Copy name in product id field
  698. memcpy(udi_msc_inquiry_data.product_id,
  699. mem_name(udi_msc_cbw.bCBWLUN)+1, // To remove first '"'
  700. sizeof(udi_msc_inquiry_data.product_id));
  701. // Search end of name '/0' or '"'
  702. i = 0;
  703. while (sizeof(udi_msc_inquiry_data.product_id) != i) {
  704. if ((0 == udi_msc_inquiry_data.product_id[i])
  705. || ('"' == udi_msc_inquiry_data.product_id[i])) {
  706. break;
  707. }
  708. i++;
  709. }
  710. // Padding with space char
  711. while (sizeof(udi_msc_inquiry_data.product_id) != i) {
  712. udi_msc_inquiry_data.product_id[i] = ' ';
  713. i++;
  714. }
  715. // Send inquiry data
  716. udi_msc_data_send((uint8_t *) & udi_msc_inquiry_data, length);
  717. }
  718. static bool udi_msc_spc_testunitready_global(void)
  719. {
  720. switch (mem_test_unit_ready(udi_msc_cbw.bCBWLUN)) {
  721. case CTRL_GOOD:
  722. return true; // Don't change sense data
  723. case CTRL_BUSY:
  724. udi_msc_sense_fail_busy_or_change();
  725. break;
  726. case CTRL_NO_PRESENT:
  727. udi_msc_sense_fail_not_present();
  728. break;
  729. case CTRL_FAIL:
  730. default:
  731. udi_msc_sense_fail_hardware();
  732. break;
  733. }
  734. return false;
  735. }
  736. static void udi_msc_spc_testunitready(void)
  737. {
  738. if (udi_msc_spc_testunitready_global()) {
  739. // LUN ready, then update sense data with status pass
  740. udi_msc_sense_pass();
  741. }
  742. // Send status in CSW packet
  743. udi_msc_csw_process();
  744. }
  745. static void udi_msc_spc_mode_sense(bool b_sense10)
  746. {
  747. // Union of all mode sense structures
  748. union sense_6_10 {
  749. struct {
  750. struct scsi_mode_param_header6 header;
  751. struct spc_control_page_info_execpt sense_data;
  752. } s6;
  753. struct {
  754. struct scsi_mode_param_header10 header;
  755. struct spc_control_page_info_execpt sense_data;
  756. } s10;
  757. };
  758. uint8_t data_sense_lgt;
  759. uint8_t mode;
  760. uint8_t request_lgt;
  761. uint8_t wp;
  762. struct spc_control_page_info_execpt *ptr_mode;
  763. UDC_BSS(4) static union sense_6_10 sense;
  764. // Clear all fields
  765. memset(&sense, 0, sizeof(sense));
  766. // Initialize process
  767. if (b_sense10) {
  768. request_lgt = udi_msc_cbw.CDB[8];
  769. ptr_mode = &sense.s10.sense_data;
  770. data_sense_lgt = sizeof(struct scsi_mode_param_header10);
  771. } else {
  772. request_lgt = udi_msc_cbw.CDB[4];
  773. ptr_mode = &sense.s6.sense_data;
  774. data_sense_lgt = sizeof(struct scsi_mode_param_header6);
  775. }
  776. // No Block descriptor
  777. // Fill page(s)
  778. mode = udi_msc_cbw.CDB[2] & SCSI_MS_MODE_ALL;
  779. if ((SCSI_MS_MODE_INFEXP == mode)
  780. || (SCSI_MS_MODE_ALL == mode)) {
  781. // Informational exceptions control page (from SPC)
  782. ptr_mode->page_code =
  783. SCSI_MS_MODE_INFEXP;
  784. ptr_mode->page_length =
  785. SPC_MP_INFEXP_PAGE_LENGTH;
  786. ptr_mode->mrie =
  787. SPC_MP_INFEXP_MRIE_NO_SENSE;
  788. data_sense_lgt += sizeof(struct spc_control_page_info_execpt);
  789. }
  790. // Can't send more than mode sense data length
  791. if (request_lgt > data_sense_lgt)
  792. request_lgt = data_sense_lgt;
  793. if (!udi_msc_cbw_validate(request_lgt, USB_CBW_DIRECTION_IN))
  794. return;
  795. // Fill mode parameter header length
  796. wp = (mem_wr_protect(udi_msc_cbw.bCBWLUN)) ? SCSI_MS_SBC_WP : 0;
  797. if (b_sense10) {
  798. sense.s10.header.mode_data_length =
  799. cpu_to_be16((data_sense_lgt - 2));
  800. //sense.s10.header.medium_type = 0;
  801. sense.s10.header.device_specific_parameter = wp;
  802. //sense.s10.header.block_descriptor_length = 0;
  803. } else {
  804. sense.s6.header.mode_data_length = data_sense_lgt - 1;
  805. //sense.s6.header.medium_type = 0;
  806. sense.s6.header.device_specific_parameter = wp;
  807. //sense.s6.header.block_descriptor_length = 0;
  808. }
  809. // Send mode sense data
  810. udi_msc_data_send((uint8_t *) & sense, request_lgt);
  811. }
  812. static void udi_msc_spc_prevent_allow_medium_removal(void)
  813. {
  814. uint8_t prevent = udi_msc_cbw.CDB[4];
  815. if (0 == prevent) {
  816. udi_msc_sense_pass();
  817. } else {
  818. udi_msc_sense_fail_cdb_invalid(); // Command is unsupported
  819. }
  820. udi_msc_csw_process();
  821. }
  822. static void udi_msc_sbc_start_stop(void)
  823. {
  824. bool start = 0x1 & udi_msc_cbw.CDB[4];
  825. bool loej = 0x2 & udi_msc_cbw.CDB[4];
  826. if (loej) {
  827. mem_unload(udi_msc_cbw.bCBWLUN, !start);
  828. }
  829. udi_msc_sense_pass();
  830. udi_msc_csw_process();
  831. }
  832. static void udi_msc_sbc_read_capacity(void)
  833. {
  834. UDC_BSS(4) static struct sbc_read_capacity10_data udi_msc_capacity;
  835. if (!udi_msc_cbw_validate(sizeof(udi_msc_capacity),
  836. USB_CBW_DIRECTION_IN))
  837. return;
  838. // Get capacity of LUN
  839. switch (mem_read_capacity(udi_msc_cbw.bCBWLUN,
  840. &udi_msc_capacity.max_lba)) {
  841. case CTRL_GOOD:
  842. break;
  843. case CTRL_BUSY:
  844. udi_msc_sense_fail_busy_or_change();
  845. udi_msc_csw_process();
  846. return;
  847. case CTRL_NO_PRESENT:
  848. udi_msc_sense_fail_not_present();
  849. udi_msc_csw_process();
  850. return;
  851. default:
  852. udi_msc_sense_fail_hardware();
  853. udi_msc_csw_process();
  854. return;
  855. }
  856. // Format capacity data
  857. udi_msc_capacity.block_len = CPU_TO_BE32(UDI_MSC_BLOCK_SIZE);
  858. udi_msc_capacity.max_lba = cpu_to_be32(udi_msc_capacity.max_lba);
  859. // Send the corresponding sense data
  860. udi_msc_data_send((uint8_t *) & udi_msc_capacity,
  861. sizeof(udi_msc_capacity));
  862. }
  863. static void udi_msc_sbc_trans(bool b_read)
  864. {
  865. uint32_t trans_size;
  866. if (!b_read) {
  867. // Write operation then check Write Protect
  868. if (mem_wr_protect(udi_msc_cbw.bCBWLUN)) {
  869. // Write not authorized
  870. udi_msc_sense_fail_protected();
  871. udi_msc_csw_process();
  872. return;
  873. }
  874. }
  875. // Read/Write command fields (address and number of block)
  876. MSB0(udi_msc_addr) = udi_msc_cbw.CDB[2];
  877. MSB1(udi_msc_addr) = udi_msc_cbw.CDB[3];
  878. MSB2(udi_msc_addr) = udi_msc_cbw.CDB[4];
  879. MSB3(udi_msc_addr) = udi_msc_cbw.CDB[5];
  880. MSB(udi_msc_nb_block) = udi_msc_cbw.CDB[7];
  881. LSB(udi_msc_nb_block) = udi_msc_cbw.CDB[8];
  882. // Compute number of byte to transfer and valid it
  883. trans_size = (uint32_t) udi_msc_nb_block *UDI_MSC_BLOCK_SIZE;
  884. if (!udi_msc_cbw_validate(trans_size,
  885. (b_read) ? USB_CBW_DIRECTION_IN :
  886. USB_CBW_DIRECTION_OUT))
  887. return;
  888. // Record transfer request to do it in a task and not under interrupt
  889. udi_msc_b_read = b_read;
  890. udi_msc_b_trans_req = true;
  891. UDI_MSC_NOTIFY_TRANS_EXT();
  892. }
  893. bool udi_msc_process_trans(void)
  894. {
  895. Ctrl_status status;
  896. if (!udi_msc_b_trans_req)
  897. return false; // No Transfer request to do
  898. udi_msc_b_trans_req = false;
  899. udi_msc_b_reset_trans = false;
  900. // Start transfer
  901. if (udi_msc_b_read) {
  902. status = memory_2_usb(udi_msc_cbw.bCBWLUN, udi_msc_addr,
  903. udi_msc_nb_block);
  904. } else {
  905. status = usb_2_memory(udi_msc_cbw.bCBWLUN, udi_msc_addr,
  906. udi_msc_nb_block);
  907. }
  908. // Check if transfer is aborted by reset
  909. if (udi_msc_b_reset_trans) {
  910. udi_msc_b_reset_trans = false;
  911. return true;
  912. }
  913. // Check status of transfer
  914. switch (status) {
  915. case CTRL_GOOD:
  916. udi_msc_sense_pass();
  917. break;
  918. case CTRL_BUSY:
  919. udi_msc_sense_fail_busy_or_change();
  920. break;
  921. case CTRL_NO_PRESENT:
  922. udi_msc_sense_fail_not_present();
  923. break;
  924. default:
  925. case CTRL_FAIL:
  926. udi_msc_sense_fail_hardware();
  927. break;
  928. }
  929. // Send status of transfer in CSW packet
  930. udi_msc_csw_process();
  931. return true;
  932. }
  933. static void udi_msc_trans_ack(udd_ep_status_t status, iram_size_t n,
  934. udd_ep_id_t ep)
  935. {
  936. UNUSED(ep);
  937. UNUSED(n);
  938. // Update variable to signal the end of transfer
  939. udi_msc_b_abort_trans = (UDD_EP_TRANSFER_OK != status) ? true : false;
  940. udi_msc_b_ack_trans = true;
  941. }
  942. bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size,
  943. void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep))
  944. {
  945. if (!udi_msc_b_ack_trans)
  946. return false; // No possible, transfer on going
  947. // Start transfer Internal RAM<->USB line
  948. udi_msc_b_ack_trans = false;
  949. if (!udd_ep_run((b_read) ? UDI_MSC_EP_IN : UDI_MSC_EP_OUT,
  950. false,
  951. block,
  952. block_size,
  953. (NULL == callback) ? udi_msc_trans_ack :
  954. callback)) {
  955. udi_msc_b_ack_trans = true;
  956. return false;
  957. }
  958. if (NULL == callback) {
  959. while (!udi_msc_b_ack_trans);
  960. if (udi_msc_b_abort_trans) {
  961. return false;
  962. }
  963. udi_msc_csw.dCSWDataResidue -= block_size;
  964. return (!udi_msc_b_abort_trans);
  965. }
  966. udi_msc_csw.dCSWDataResidue -= block_size;
  967. return true;
  968. }
  969. //@}
  970. #endif // SDSUPPORT
  971. #endif // ARDUINO_ARCH_SAM