123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031 |
- /*
- * The Mass Storage protocol state machine in this file is based on mbed's
- * implementation. We augment it by adding Zephyr's USB transport and Storage
- * APIs.
- *
- * Copyright (c) 2010-2011 mbed.org, MIT License
- * Copyright (c) 2016 Intel Corporation.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- /**
- * @file
- * @brief Mass Storage device class driver
- *
- * Driver for USB Mass Storage device class driver
- */
- #include <init.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/byteorder.h>
- #include <usb/class/usb_msc.h>
- #include <usb/usb_device.h>
- #include <usb/usb_common.h>
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- #include <soc.h>
- #endif
- #include "mass_storage_descriptor.h"
- #define LOG_LEVEL 2
- #include <logging/log.h>
- LOG_MODULE_REGISTER(mass_storage);
- #include "diskio.h"
- /* max USB packet size */
- #if CONFIG_MASS_STORAGE_BULK_EP_MPS > USB_MAX_FS_BULK_MPS
- #define MAX_PACKET USB_MAX_FS_BULK_MPS /* Bulk MaxPakcetSize in full-speed */
- #else
- #define MAX_PACKET CONFIG_MASS_STORAGE_BULK_EP_MPS
- #endif
- /*
- * 1: USB will read all left data even if fail to write disk,
- * 0: We will just stall bulk-out endpoint and quit.
- */
- #define DISK_WRITE_ERROR_CONTINUE 1
- /*
- * 1: USB will read all data even if there is no medium.
- * 0: We will stall bulk-out endpoint.
- */
- #define MSC_WRITE_NO_MEDIUM_CONTINUE 1
- #define BLOCK_SIZE 512
- #define DISK_THREAD_STACK_SZ CONFIG_MASS_STORAGE_STACK_SIZE
- #define DISK_THREAD_PRIO CONFIG_MASS_STORAGE_PRIORITY
- #define THREAD_OP_READ_QUEUED 1
- #define THREAD_OP_READ_DONE 2
- #define THREAD_OP_WRITE_QUEUED 3
- #define THREAD_OP_WRITE_DONE 4
- /* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
- #define SS_NO_SENSE 0
- #define SS_COMMUNICATION_FAILURE 0x040800
- #define SS_INVALID_COMMAND 0x052000
- #define SS_INVALID_FIELD_IN_CDB 0x052400
- #define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
- #define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
- #define SS_MEDIUM_NOT_PRESENT 0x023a00
- #define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
- #define SS_NOT_READY_TO_READY_TRANSITION 0x062800
- #define SS_RESET_OCCURRED 0x062900
- #define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
- #define SS_UNRECOVERED_READ_ERROR 0x031100
- #define SS_WRITE_ERROR 0x030c02
- #define SS_WRITE_PROTECTED 0x072700
- #define SS_DATA_CRC_ERROR 0x0b4701
- #define SK(x) ((u8_t) ((x) >> 16)) /* Sense Key byte, etc. */
- #define ASC(x) ((u8_t) ((x) >> 8)) /* AddSenseCode*/
- #define ASCQ(x) ((u8_t) (x)) /* AddSnsCodeQlfr */
- static u32_t msc_sense_data;
- #define MSC_UNKNOWN 0
- /* MSC_RUNNING and MSC_ABORTED are mutual exceptional */
- #define MSC_RUNNING BIT(0)
- #define MSC_ABORTED BIT(1)
- #define MSC_EJECTED BIT(2)
- #define MSC_PREVENT_MEDIA_REMOVAL BIT(3)
- static u8_t msc_state;
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- static u8_t switch_to_adfu;
- static struct k_work switch_to_adfu_work;
- #endif
- static struct k_work disk_sync_work;
- static u8_t disk_sync_pdrv;
- #define SWITCH_TO_STUB_START 1
- #define SWITCH_TO_STUB_DONE 2
- static u8_t switch_to_stub;
- static inline bool msc_state_unknown(void)
- {
- return msc_state == MSC_UNKNOWN;
- }
- static inline bool msc_state_running(void)
- {
- return msc_state & MSC_RUNNING;
- }
- static inline bool msc_state_aborted(void)
- {
- return msc_state & MSC_ABORTED;
- }
- static inline bool msc_state_ejected(void)
- {
- return msc_state & MSC_EJECTED;
- }
- //static inline bool msc_state_prevent_media_removal(void)
- //{
- // return msc_state & MSC_PREVENT_MEDIA_REMOVAL;
- //}
- static inline void msc_state_set_unknown(void)
- {
- msc_state = MSC_UNKNOWN;
- }
- static inline void msc_state_set_running(void)
- {
- msc_state |= MSC_RUNNING;
- }
- static inline void msc_state_clear_running(void)
- {
- msc_state &= ~MSC_RUNNING;
- }
- static inline void msc_state_set_aborted(void)
- {
- msc_state |= MSC_ABORTED;
- }
- static inline void msc_state_set_ejected(void)
- {
- msc_state |= MSC_EJECTED;
- }
- __unused static inline void msc_state_set_prevent_media_removal(void)
- {
- msc_state |= MSC_PREVENT_MEDIA_REMOVAL;
- }
- __unused static inline void msc_state_clear_prevent_media_removal(void)
- {
- msc_state &= ~MSC_PREVENT_MEDIA_REMOVAL;
- }
- static usb_msc_eject_callback eject_cb;
- static volatile int thread_op;
- #ifndef CONFIG_USB_MASS_STORAGE_SHARE_THREAD
- static K_THREAD_STACK_DEFINE(mass_thread_stack, DISK_THREAD_STACK_SZ);
- static struct k_thread mass_thread_data;
- #endif
- static struct k_sem disk_wait_sem;
- static struct k_sem usb_wait_sem;
- static volatile u32_t defered_wr_sz;
- static volatile u32_t defered_rd_off;
- static u8_t *page;
- static u8_t *page2;
- static u32_t page_size;
- #define USB_RW_TIMEOUT K_MSEC(5000)
- static u8_t usb_rw_working;
- /* Initialized during mass_storage_init() */
- static u64_t memory_size;
- static u32_t block_count;
- static u8_t disk_pdrv = CONFIG_MASS_STORAGE_DISK_PDRV;
- #define MSD_OUT_EP_IDX 0
- #define MSD_IN_EP_IDX 1
- #ifdef CONFIG_SPINAND_ACTS
- #include <drivers/flash.h>
- #include <partition/partition.h>
- static const struct device *flash_dev;
- //#define UDISK_OFFSET 0x4a00000
- static uint32_t get_udisk_offset(void)
- {
- const struct partition_entry *parti;
- #ifdef CONFIG_BOARD_NANDBOOT
- parti = partition_get_stf_part(STORAGE_ID_BOOTNAND, PARTITION_FILE_ID_UDISK);
- #else
- parti = partition_get_stf_part(STORAGE_ID_NAND, PARTITION_FILE_ID_UDISK);
- #endif
- if (parti != NULL) {
- LOG_INF("udisk offset=0x%x secotr\n", parti->offset);
- return (parti->offset);
- }
- LOG_ERR("get udisk offset err!\n");
- return 0;
- }
- #endif
- static void mass_storage_process_suspend(void)
- {
- /* stop */
- msc_state_set_ejected();
- disk_sync_pdrv = disk_pdrv;
- /* flush memory data to medium*/
- k_work_submit(&disk_sync_work);
- disk_pdrv = MSC_DISK_NO_MEDIA;
- if (eject_cb) {
- eject_cb();
- }
- }
- static void mass_storage_bulk_out(u8_t ep,
- enum usb_dc_ep_cb_status_code ep_status);
- static void mass_storage_bulk_in(u8_t ep,
- enum usb_dc_ep_cb_status_code ep_status);
- /* Describe EndPoints configuration */
- static const struct usb_ep_cfg_data mass_ep_data[] = {
- {
- .ep_cb = mass_storage_bulk_out,
- .ep_addr = CONFIG_MASS_STORAGE_OUT_EP_ADDR
- },
- {
- .ep_cb = mass_storage_bulk_in,
- .ep_addr = CONFIG_MASS_STORAGE_IN_EP_ADDR
- }
- };
- /* CSW Status */
- enum Status {
- CSW_PASSED,
- CSW_FAILED,
- CSW_ERROR,
- };
- /* MSC Bulk-only Stage */
- enum Stage {
- READ_CBW, /* wait a CBW */
- ERROR, /* error */
- PROCESS_CBW, /* process a CBW request */
- SEND_CSW, /* send a CSW */
- WAIT_CSW /* wait that a CSW has been effectively sent */
- };
- /* state of the bulk-only state machine */
- static enum Stage stage;
- /*current CBW*/
- static struct CBW cbw __aligned(4);
- /*CSW which will be sent*/
- static struct CSW csw;
- /*addr where will be read or written data*/
- static u64_t addr;
- /* max USB packet size */
- static u32_t max_packet = MAX_PACKET;
- /*length of a reading or writing*/
- static u32_t length;
- static u8_t max_lun_count;
- /*memory OK (after a memoryVerify)*/
- static bool memOK;
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- static u8_t *usb_mass_transfer_buf;
- static u32_t usb_mass_transfer_len;
- static struct k_delayed_work usb_mass_transfer_work;
- static inline int usb_mass_transfer(u8_t *data, u32_t len)
- {
- usb_mass_transfer_buf = data;
- usb_mass_transfer_len = len;
- k_delayed_work_submit(&usb_mass_transfer_work, K_NO_WAIT);
- return 0;
- }
- static void usb_mass_transfer_handler(struct k_work *work)
- {
- if (thread_op == THREAD_OP_READ_QUEUED) {
- usb_dc_ep_write_pending(CONFIG_MASS_STORAGE_IN_EP_ADDR,
- usb_mass_transfer_buf, usb_mass_transfer_len, NULL);
- } else if (thread_op == THREAD_OP_WRITE_QUEUED) {
- usb_dc_ep_read_pending(CONFIG_MASS_STORAGE_OUT_EP_ADDR,
- usb_mass_transfer_buf, usb_mass_transfer_len, NULL);
- }
- }
- #endif /* CONFIG_USB_AOTG_DC_MULTI_FIFO */
- static inline int usb_mass_write(u8_t *data, u32_t len)
- {
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- return usb_dc_ep_write_pending(CONFIG_MASS_STORAGE_IN_EP_ADDR, data,
- len, NULL);
- #else
- return usb_write(CONFIG_MASS_STORAGE_IN_EP_ADDR, data, len, NULL);
- #endif
- }
- static inline int usb_mass_read(u8_t *data, u32_t len)
- {
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- return usb_dc_ep_read_pending(CONFIG_MASS_STORAGE_OUT_EP_ADDR, data,
- len, NULL);
- #else
- return usb_read_async(CONFIG_MASS_STORAGE_OUT_EP_ADDR, data, len, NULL);
- #endif
- }
- static void msd_state_machine_reset(void)
- {
- stage = READ_CBW;
- }
- static void msd_init(void)
- {
- memset((void *)&cbw, 0, sizeof(struct CBW));
- memset((void *)&csw, 0, sizeof(struct CSW));
- addr = 0;
- length = 0;
- defered_wr_sz = 0;
- defered_rd_off = 0;
- }
- static bool sendCSW(void)
- {
- csw.Signature = CSW_Signature;
- stage = WAIT_CSW;
- if (usb_mass_write((u8_t *)&csw, sizeof(struct CSW)) != 0) {
- LOG_ERR("usb write failure");
- return false;
- }
- return true;
- }
- static bool write(u8_t *buf, u16_t size)
- {
- if (size >= cbw.DataLength) {
- size = cbw.DataLength;
- }
- /* updating the State Machine , so that we send CSW when this
- * transfer is complete, ie when we get a bulk in callback
- */
- stage = SEND_CSW;
- csw.DataResidue -= size;
- if (usb_mass_write(buf, size)) {
- LOG_ERR("USB write failed");
- return false;
- }
- return true;
- }
- /**
- * @brief Handler called for Class requests not handled by the USB stack.
- *
- * @param pSetup Information about the request to execute.
- * @param len Size of the buffer.
- * @param data Buffer containing the request result.
- *
- * @return 0 on success, negative errno code on fail.
- */
- static int mass_storage_class_handle_req(struct usb_setup_packet *pSetup,
- s32_t *len, u8_t **data)
- {
- switch (pSetup->bRequest) {
- case MSC_REQUEST_RESET:
- LOG_DBG("MSC_REQUEST_RESET");
- if (sys_le16_to_cpu(pSetup->wLength)) {
- LOG_WRN("Invalid length");
- return -EINVAL;
- }
- msd_state_machine_reset();
- usb_mass_read((u8_t *)&cbw, sizeof(cbw));
- break;
- case MSC_REQUEST_GET_MAX_LUN:
- LOG_DBG("MSC_REQUEST_GET_MAX_LUN");
- if (sys_le16_to_cpu(pSetup->wLength) != 1) {
- LOG_WRN("Invalid length");
- return -EINVAL;
- }
- max_lun_count = 0;
- *data = (u8_t *)(&max_lun_count);
- *len = 1;
- break;
- default:
- LOG_WRN("Unknown request 0x%x, value 0x%x",
- pSetup->bRequest, pSetup->wValue);
- return -EINVAL;
- }
- return 0;
- }
- static void testUnitReady(void)
- {
- if (cbw.DataLength != 0) {
- if ((cbw.Flags & 0x80) != 0) {
- LOG_WRN("Stall IN endpoint");
- usb_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- } else {
- LOG_WRN("Stall OUT endpoint");
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- }
- }
- if ((disk_pdrv == MSC_DISK_NO_LUN) ||
- (disk_pdrv == MSC_DISK_NO_MEDIA)) {
- csw.Status = CSW_FAILED;
- } else {
- csw.Status = CSW_PASSED;
- }
- sendCSW();
- }
- static bool requestSense(void)
- {
- u8_t request_sense[] = {
- 0x70,
- 0x00,
- 0x05, /* Sense Key: illegal request */
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x0A,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x30,
- 0x01,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- };
- if (msc_sense_data == SS_NO_SENSE) {
- if (disk_pdrv == MSC_DISK_NO_LUN) {
- msc_sense_data = SS_LOGICAL_UNIT_NOT_SUPPORTED;
- } else if (disk_pdrv == MSC_DISK_NO_MEDIA) {
- msc_sense_data = SS_MEDIUM_NOT_PRESENT;
- }
- }
- if (msc_sense_data) {
- request_sense[2] = SK(msc_sense_data);
- request_sense[12] = ASC(msc_sense_data);
- request_sense[13] = ASCQ(msc_sense_data);
- }
- msc_sense_data = SS_NO_SENSE;
- csw.Status = CSW_PASSED;
- return write(request_sense, sizeof(request_sense));
- }
- static bool inquiryRequest(void)
- {
- /*
- * inquiry[2]: ANSI SCSI level 2
- * inquiry[3]: SCSI-2 INQUIRY data format
- */
- u8_t inquiry[] = { 0x00, 0x80, 0x02, 0x02,
- 36 - 4, 0x00, 0x00, 0x00,
- 'Z', 'E', 'P', 'H', 'Y', 'R', ' ', ' ',
- 'Z', 'E', 'P', 'H', 'Y', 'R', ' ', 'U', 'S', 'B', ' ',
- 'D', 'I', 'S', 'K', ' ',
- '0', '.', '0', '1',
- };
- csw.Status = CSW_PASSED;
- return write(inquiry, sizeof(inquiry));
- }
- static bool modeSense6(void)
- {
- u8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
- #ifdef CONFIG_MASS_STORAGE_WP
- sense6[2] = 0x80;
- #endif
- csw.Status = CSW_PASSED;
- return write(sense6, sizeof(sense6));
- }
- static bool modeSense10(void)
- {
- u8_t sense10[] = { 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- #ifdef CONFIG_MASS_STORAGE_WP
- sense10[3] = 0x80;
- #endif
- csw.Status = CSW_PASSED;
- return write(sense10, sizeof(sense10));
- }
- static bool readFormatCapacity(void)
- {
- u8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
- (u8_t)((block_count >> 24) & 0xff),
- (u8_t)((block_count >> 16) & 0xff),
- (u8_t)((block_count >> 8) & 0xff),
- (u8_t)((block_count >> 0) & 0xff),
- 0x02,
- (u8_t)((BLOCK_SIZE >> 16) & 0xff),
- (u8_t)((BLOCK_SIZE >> 8) & 0xff),
- (u8_t)((BLOCK_SIZE >> 0) & 0xff),
- };
- csw.Status = CSW_PASSED;
- return write(capacity, sizeof(capacity));
- }
- static bool readCapacity(void)
- {
- u8_t capacity[] = {
- (u8_t)(((block_count - 1) >> 24) & 0xff),
- (u8_t)(((block_count - 1) >> 16) & 0xff),
- (u8_t)(((block_count - 1) >> 8) & 0xff),
- (u8_t)(((block_count - 1) >> 0) & 0xff),
- (u8_t)((BLOCK_SIZE >> 24) & 0xff),
- (u8_t)((BLOCK_SIZE >> 16) & 0xff),
- (u8_t)((BLOCK_SIZE >> 8) & 0xff),
- (u8_t)((BLOCK_SIZE >> 0) & 0xff),
- };
- csw.Status = CSW_PASSED;
- return write(capacity, sizeof(capacity));
- }
- static bool do_cmd_inquiry_adfu(void)
- {
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- u8_t data[11];
- stage = SEND_CSW;
- csw.DataResidue = 0;
- csw.Status = CSW_PASSED;
- memcpy(data, "ACTIONSUSBD", sizeof(data));
- if (usb_mass_write(data, sizeof(data))) {
- LOG_ERR("USB write failed");
- return false;
- }
- return true;
- #else
- stage = SEND_CSW;
- csw.DataResidue = 0;
- csw.Status = CSW_FAILED;
- /* send 0-length packet */
- if (usb_mass_write(NULL, 0)) {
- LOG_ERR("USB write failed");
- return false;
- }
- return true;
- #endif
- }
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- static bool do_cmd_switch_to_adfu(void)
- {
- u8_t data[2] = { 0xff, 0x55 };
- stage = SEND_CSW;
- switch_to_adfu = 1;
- csw.DataResidue = 0;
- csw.Status = CSW_PASSED;
- /* send 0-length packet */
- if (usb_mass_write(data, sizeof(data))) {
- LOG_ERR("USB write failed");
- return false;
- }
- return true;
- }
- #endif
- static bool do_cmd_adfu_misc(void)
- {
- LOG_DBG("0x%x", cbw.CB[1]);
- switch (cbw.CB[1]) {
- case ADFU_MISC_RESTART:
- break;
- case ADFU_MISC_SET_SERIAL_NUMBER:
- break;
- case ADFU_MISC_GET_SERIAL_NUMBER:
- break;
- case ADFU_MISC_SET_MISCINFO:
- break;
- case ADFU_MISC_GET_MISCINFO:
- break;
- case ADFU_MISC_GET_CHIPID:
- break;
- case ADFU_MISC_SWITCH_TO_STUB:
- if (cbw.CB[2] == 0x01) {
- switch_to_stub = SWITCH_TO_STUB_START;
- csw.Status = CSW_PASSED;
- return sendCSW();
- }
- break;
- default:
- break;
- }
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- csw.Status = CSW_ERROR;
- sendCSW();
- return false;
- }
- #include <drivers/rtc.h>
- static void set_time_and_date(void)
- {
- u8_t *temp_buff = (u8_t *)&cbw;
- struct rtc_time time = {0};
- const struct device *rtc = NULL;
- #ifdef CONFIG_RTC_0_NAME
- rtc = device_get_binding(CONFIG_RTC_0_NAME);
- #endif
- time.tm_year = temp_buff[0] | (temp_buff[1]<<8);
- time.tm_mon = temp_buff[2];
- time.tm_mday = temp_buff[3];
- time.tm_hour = temp_buff[4];
- time.tm_min = temp_buff[5];
- time.tm_sec = temp_buff[6];
- time.tm_ms = 500;
- time.tm_year -= 1900; // years since 1900
- time.tm_mon --; // month 0~11
- if (rtc)
- rtc_set_time(rtc, &time);
- csw.Status = CSW_PASSED;
- sendCSW();
- return;
- }
- static __unused void thread_memory_read_done(void)
- {
- u32_t n;
- n = (length > max_packet) ? max_packet : length;
- if ((addr + n) > memory_size) {
- n = memory_size - addr;
- stage = ERROR;
- }
- addr += n;
- length -= n;
- defered_rd_off += n;
- csw.DataResidue -= n;
- if (!length || (stage != PROCESS_CBW)) {
- csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
- stage = (stage == PROCESS_CBW) ? SEND_CSW : stage;
- }
- thread_op = THREAD_OP_READ_DONE;
- if (usb_mass_write(page, n) != 0) {
- LOG_ERR("Failed to write EP 0x%x",
- mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- }
- }
- static __unused void memoryRead(void)
- {
- u32_t n, offset;
- n = (length > max_packet) ? max_packet : length;
- if ((addr + n) > memory_size) {
- n = memory_size - addr;
- stage = ERROR;
- }
- /* read data */
- if ((defered_rd_off == 0) || (defered_rd_off == page_size)) {
- thread_op = THREAD_OP_READ_QUEUED;
- LOG_DBG("Signal thread for %d", (u32_t)(addr/BLOCK_SIZE));
- k_sem_give(&disk_wait_sem);
- return;
- }
- addr += n;
- length -= n;
- csw.DataResidue -= n;
- offset = defered_rd_off;
- if (!length || (stage != PROCESS_CBW)) {
- csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
- stage = (stage == PROCESS_CBW) ? SEND_CSW : stage;
- }
- defered_rd_off += n;
- usb_mass_write(&page[offset], n);
- }
- static bool infoTransfer(void)
- {
- u64_t n = 0;
- /* Logical Block Address of First Block */
- n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] << 8) |
- (cbw.CB[5] << 0);
- LOG_DBG("LBA (block) : 0x%x ", (u32_t)n);
- addr = n * BLOCK_SIZE;
- if (addr > memory_size) {
- LOG_WRN("lba: 0x%x", (u32_t)n);
- csw.Status = CSW_FAILED;
- sendCSW();
- return false;
- }
- /* Number of Blocks to transfer */
- switch (cbw.CB[0]) {
- case READ10:
- case WRITE10:
- case VERIFY10:
- n = (cbw.CB[7] << 8) | (cbw.CB[8] << 0);
- break;
- case READ12:
- case WRITE12:
- n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) |
- (cbw.CB[8] << 8) | (cbw.CB[9] << 0);
- break;
- }
- LOG_DBG("Size (block) : 0x%x ", (u32_t)n);
- length = n * BLOCK_SIZE;
- if ((addr + length) > memory_size) {
- LOG_WRN("lba: 0x%x, size: 0x%x", (u32_t)addr/BLOCK_SIZE,
- (u32_t)n);
- csw.Status = CSW_FAILED;
- sendCSW();
- return false;
- }
- if (!cbw.DataLength) { /* host requests no data*/
- LOG_WRN("Zero length in CBW");
- csw.Status = CSW_FAILED;
- sendCSW();
- return false;
- }
- if (cbw.DataLength != length) {
- if ((cbw.Flags & 0x80) != 0) {
- LOG_WRN("Stall IN endpoint");
- usb_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- } else {
- LOG_WRN("Stall OUT endpoint");
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- }
- csw.Status = CSW_FAILED;
- sendCSW();
- return false;
- }
- return true;
- }
- static void fail(void)
- {
- csw.Status = CSW_FAILED;
- sendCSW();
- }
- static void CBWDecode(u8_t *buf, u16_t size)
- {
- if (cbw.Signature != CBW_Signature) {
- LOG_ERR("CBW Signature Mismatch 0x%x", cbw.Signature);
- return;
- }
- csw.Tag = cbw.Tag;
- csw.DataResidue = cbw.DataLength;
- if ((cbw.CBLength < 1) || (cbw.CBLength > 16) || (cbw.LUN != 0)) {
- LOG_DBG("cbw.CBLength %d", cbw.CBLength);
- fail();
- } else {
- switch (cbw.CB[0]) {
- case TEST_UNIT_READY:
- case REQUEST_SENSE:
- case INQUIRY:
- case CMD_INQUIRY_ADFU:
- case CMD_SWITCH_TO_ADFU:
- case CMD_ADFU_MISC:
- case CMD_SET_TIME_AND_DATE:
- #if MSC_WRITE_NO_MEDIUM_CONTINUE
- case WRITE10:
- case WRITE12:
- #endif
- break;
- default:
- /* if no lun or no media */
- if ((disk_pdrv == MSC_DISK_NO_LUN) ||
- (disk_pdrv == MSC_DISK_NO_MEDIA)) {
- if ((cbw.Flags & 0x80) || (cbw.DataLength == 0)) {
- /* Halt bulk-in endpoint */
- usb_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- } else {
- /* Halt bulk-out endpoint */
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- usb_dc_ep_flush(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- }
- fail();
- return;
- }
- break;
- }
- switch (cbw.CB[0]) {
- case TEST_UNIT_READY:
- LOG_DBG(">> TUR");
- testUnitReady();
- break;
- case REQUEST_SENSE:
- LOG_DBG(">> REQ_SENSE");
- requestSense();
- break;
- case INQUIRY:
- LOG_DBG(">> INQ");
- inquiryRequest();
- break;
- case MODE_SENSE6:
- LOG_DBG(">> MODE_SENSE6");
- modeSense6();
- break;
- case MODE_SENSE10:
- LOG_DBG(">> MODE_SENSE10");
- modeSense10();
- break;
- case READ_FORMAT_CAPACITIES:
- LOG_DBG(">> READ_FORMAT_CAPACITY");
- readFormatCapacity();
- break;
- case READ_CAPACITY:
- LOG_DBG(">> READ_CAPACITY");
- readCapacity();
- break;
- case READ10:
- case READ12:
- LOG_DBG(">> READ");
- if (infoTransfer()) {
- if ((cbw.Flags & 0x80)) {
- stage = PROCESS_CBW;
- defered_rd_off = 0;
- thread_op = THREAD_OP_READ_QUEUED;
- k_sem_init(&usb_wait_sem, 0, 1);
- LOG_DBG("Signal thread for %d",
- (u32_t)(addr/BLOCK_SIZE));
- k_sem_give(&disk_wait_sem);
- } else {
- usb_ep_set_stall(
- mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- LOG_DBG("Stall OUT endpoint");
- csw.Status = CSW_ERROR;
- sendCSW();
- }
- }
- break;
- case WRITE10:
- case WRITE12:
- LOG_DBG(">> WRITE");
- if (infoTransfer()) {
- if (!(cbw.Flags & 0x80)) {
- stage = PROCESS_CBW;
- thread_op = THREAD_OP_WRITE_QUEUED; /* write_queued */
- k_sem_init(&usb_wait_sem, 0, 1);
- k_sem_give(&disk_wait_sem);
- } else {
- usb_ep_set_stall(
- mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- LOG_DBG("Stall IN endpoint");
- csw.Status = CSW_ERROR;
- sendCSW();
- }
- }
- break;
- #if 0
- case VERIFY10:
- LOG_DBG(">> VERIFY10");
- if (!(cbw.CB[1] & 0x02)) {
- csw.Status = CSW_PASSED;
- sendCSW();
- break;
- }
- if (infoTransfer()) {
- if (!(cbw.Flags & 0x80)) {
- stage = PROCESS_CBW;
- memOK = true;
- } else {
- usb_ep_set_stall(
- mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- LOG_WRN("Stall IN endpoint");
- csw.Status = CSW_ERROR;
- sendCSW();
- }
- }
- break;
- #endif
- case MEDIA_REMOVAL:
- LOG_DBG(">> MEDIA_REMOVAL");
- /*
- * FIXME: if prevent bit set, we are not allowed to
- * unload the media.
- */
- csw.Status = CSW_PASSED;
- sendCSW();
- break;
- case START_STOP_UNIT:
- LOG_DBG(">> START_STOP_UNIT");
- /* respond CSW first */
- csw.Status = CSW_PASSED;
- sendCSW();
- /* LOEJ: load eject bit */
- if (!(cbw.CB[4] & 0x02)) {
- break;
- }
- /* START: start bit */
- if (!(cbw.CB[4] & 0x01)) {
- if (eject_cb) {
- eject_cb();
- }
- msc_state_set_ejected();
- msc_sense_data = SS_MEDIUM_NOT_PRESENT;
- } else {
- if (!msc_state_running()) {
- msc_sense_data = SS_MEDIUM_NOT_PRESENT;
- }
- }
- break;
- case CMD_INQUIRY_ADFU:
- LOG_DBG(">> INQUIRY_ADFU");
- do_cmd_inquiry_adfu();
- break;
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- case CMD_SWITCH_TO_ADFU:
- LOG_DBG(">> SWITCH_TO_ADFU");
- do_cmd_switch_to_adfu();
- break;
- #endif
- case CMD_ADFU_MISC:
- LOG_DBG(">> ADFU_MISC");
- do_cmd_adfu_misc();
- break;
- case CMD_SET_TIME_AND_DATE:
- LOG_DBG(">> SET_TIME_AND_DATE");
- usb_mass_read((u8_t *)&cbw, 7);
- stage = PROCESS_CBW;
- break;
- default:
- LOG_DBG(">> default CB[0] %x", cbw.CB[0]);
- fail();
- break;
- } /*switch(cbw.CB[0])*/
- } /* else */
- }
- static __unused void memoryVerify(u8_t *buf, u16_t size)
- {
- u32_t n;
- if ((addr + size) > memory_size) {
- size = memory_size - addr;
- stage = ERROR;
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- LOG_WRN("Stall OUT endpoint");
- }
- /* beginning of a new block -> load a whole block in RAM */
- #ifdef CONFIG_SPINAND_ACTS
- u32_t offset = get_udisk_offset();
- if (!((addr+offset) % BLOCK_SIZE)) {
- LOG_DBG("Flash READ sector %d", (u32_t)((addr+offset)/BLOCK_SIZE));
- if (offset != 0) {
- if (flash_read(flash_dev, (addr+offset), page, 1<<9)) {
- LOG_ERR("---- Flash Read Error %d", (u32_t)((addr+offset)/BLOCK_SIZE));
- }
- }
- }
- #else
- if (!(addr % BLOCK_SIZE)) {
- LOG_DBG("Disk READ sector %d", (u32_t)(addr/BLOCK_SIZE));
- if (disk_read(disk_pdrv, page, addr/BLOCK_SIZE, 1)) {
- LOG_ERR("---- Disk Read Error %d", (u32_t)(addr/BLOCK_SIZE));
- }
- }
- #endif
- /* info are in RAM -> no need to re-read memory */
- for (n = 0; n < size; n++) {
- if (page[addr%BLOCK_SIZE + n] != buf[n]) {
- LOG_DBG("Mismatch sector %d offset %d",
- (u32_t)(addr/BLOCK_SIZE), (u32_t)n);
- memOK = false;
- break;
- }
- }
- addr += size;
- length -= size;
- csw.DataResidue -= size;
- if (!length || (stage != PROCESS_CBW)) {
- csw.Status = (memOK && (stage == PROCESS_CBW)) ?
- CSW_PASSED : CSW_FAILED;
- sendCSW();
- }
- }
- static __unused void memoryWrite(u8_t *buf, u16_t size)
- {
- if ((addr + size) > memory_size) {
- size = memory_size - addr;
- stage = ERROR;
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- LOG_WRN("Stall OUT endpoint");
- }
- memcpy(page + defered_wr_sz, buf, size);
- length -= size;
- defered_wr_sz += size;
- csw.DataResidue -= size;
- /* if the array is filled, write it in memory */
- if ((defered_wr_sz == page_size) || (length == 0)) {
- if (!(disk_status(disk_pdrv) & STA_PROTECT)) {
- LOG_DBG("Disk WRITE Qd %d", (u32_t)(addr/BLOCK_SIZE));
- thread_op = THREAD_OP_WRITE_QUEUED; /* write_queued */
- k_sem_give(&disk_wait_sem);
- return;
- }
- }
- if ((!length) || (stage != PROCESS_CBW)) {
- csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
- sendCSW();
- }
- }
- static void mass_storage_bulk_out(u8_t ep,
- enum usb_dc_ep_cb_status_code ep_status)
- {
- ARG_UNUSED(ep_status);
- switch (stage) {
- /*the device has to decode the CBW received*/
- case READ_CBW:
- LOG_DBG("> BO - READ_CBW");
- CBWDecode((u8_t *)&cbw, sizeof(cbw));
- break;
- /*the device has to receive data from the host*/
- case PROCESS_CBW:
- switch (cbw.CB[0]) {
- case WRITE10:
- case WRITE12:
- LOG_DBG("> BO - PROC_CBW WR");
- usb_rw_working = 0;
- k_sem_give(&usb_wait_sem);
- break;
- case CMD_SET_TIME_AND_DATE:
- set_time_and_date();
- break;
- #if 0
- case VERIFY10:
- LOG_DBG("> BO - PROC_CBW VER");
- memoryVerify(bo_buf, bytes_read);
- break;
- #endif
- default:
- LOG_ERR("> BO - PROC_CBW default"
- "<<ERROR!!!>> 0x%x", cbw.CB[0]);
- break;
- }
- break;
- /*an error has occurred: stall endpoint and send CSW*/
- default:
- LOG_WRN("Stall OUT endpoint, stage: %d", stage);
- usb_ep_set_stall(ep);
- csw.Status = CSW_ERROR;
- sendCSW();
- break;
- }
- }
- static __unused void thread_memory_write_done(void)
- {
- addr += defered_wr_sz;
- defered_wr_sz = 0;
- thread_op = THREAD_OP_WRITE_DONE;
- usb_ep_read_continue(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- if ((!length) || (stage != PROCESS_CBW)) {
- csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
- sendCSW();
- }
- }
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- static void switch_to_adfu_work_handler(struct k_work *work)
- {
- usb_mass_storage_exit();
- sys_pm_reboot(REBOOT_TYPE_GOTO_ADFU);
- LOG_INF("switch to adfu");
- /* If no delay 1s, adfu will be a probability(about 1/10) of failure */
- k_sleep(K_MSEC(1000));
- }
- #endif
- /* flush memory data to storage medium */
- static void disk_sync_work_handler(struct k_work *work)
- {
- if (disk_ioctl(disk_sync_pdrv, CTRL_SYNC, NULL)) {
- LOG_WRN("MSC disk sync failed");
- }
- }
- /**
- * @brief EP Bulk IN handler, used to send data to the Host
- *
- * @param ep Endpoint address.
- * @param ep_status Endpoint status code.
- *
- * @return N/A.
- */
- static void mass_storage_bulk_in(u8_t ep,
- enum usb_dc_ep_cb_status_code ep_status)
- {
- ARG_UNUSED(ep_status);
- ARG_UNUSED(ep);
- switch (stage) {
- /*the device has to send data to the host*/
- case PROCESS_CBW:
- switch (cbw.CB[0]) {
- case READ10:
- case READ12:
- /* LOG_DBG("< BI - PROC_CBW READ"); */
- usb_rw_working = 0;
- k_sem_give(&usb_wait_sem);
- break;
- default:
- LOG_ERR("< BI-PROC_CBW default <<ERROR!!>> 0x%x",
- cbw.CB[0]);
- break;
- }
- break;
- /*the device has to send a CSW*/
- case SEND_CSW:
- LOG_DBG("< BI - SEND_CSW");
- sendCSW();
- break;
- /*the host has received the CSW -> we wait a CBW*/
- case WAIT_CSW:
- LOG_DBG("< BI - WAIT_CSW");
- stage = READ_CBW;
- usb_mass_read((u8_t *)&cbw, sizeof(cbw));
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- if (switch_to_adfu) {
- k_work_submit(&switch_to_adfu_work);
- }
- #endif
- if (switch_to_stub == SWITCH_TO_STUB_START) {
- switch_to_stub = SWITCH_TO_STUB_DONE;
- }
- break;
- /*an error has occurred*/
- default:
- LOG_WRN("Stall IN endpoint, stage: %d", stage);
- usb_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- sendCSW();
- break;
- }
- }
- /**
- * @brief Callback used to know the USB connection status
- *
- * @param status USB device status code.
- *
- * @return N/A.
- */
- static void mass_storage_status_cb(enum usb_dc_status_code status, u8_t *param)
- {
- ARG_UNUSED(param);
- /* Check the USB status and do needed action if required */
- switch (status) {
- case USB_DC_ERROR:
- LOG_DBG("USB device error");
- break;
- case USB_DC_RESET:
- LOG_DBG("USB device reset detected");
- msd_state_machine_reset();
- msd_init();
- break;
- case USB_DC_CONNECTED:
- LOG_DBG("USB device connected");
- break;
- case USB_DC_CONFIGURED:
- LOG_DBG("USB device configured");
- usb_mass_read((u8_t *)&cbw, sizeof(cbw));
- break;
- case USB_DC_DISCONNECTED:
- LOG_DBG("USB device disconnected");
- break;
- case USB_DC_SUSPEND:
- LOG_DBG("USB device supended");
- mass_storage_process_suspend();
- break;
- case USB_DC_RESUME:
- LOG_DBG("USB device resumed");
- break;
- case USB_DC_HIGHSPEED:
- /* Update MaxPacketSize */
- max_packet = USB_MAX_HS_BULK_MPS;
- break;
- case USB_DC_UNKNOWN:
- default:
- LOG_DBG("USB unknown state");
- break;
- }
- }
- /* Configuration of the Mass Storage Device send to the USB Driver */
- static const struct usb_cfg_data mass_storage_config = {
- .usb_device_description = NULL,
- .cb_usb_status = mass_storage_status_cb,
- .interface = {
- .class_handler = mass_storage_class_handle_req,
- .custom_handler = NULL,
- },
- .num_endpoints = ARRAY_SIZE(mass_ep_data),
- .endpoint = mass_ep_data
- };
- /* retry to make sure CSW succeed */
- static int handle_csw(void)
- {
- u8_t retry = 3;
- do {
- if (sendCSW()) {
- goto done;
- }
- k_busy_wait(100);
- LOG_WRN("retry");
- } while (--retry);
- /* fail */
- usb_dc_ep_flush(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- csw.Status = CSW_FAILED;
- LOG_ERR("failed");
- sendCSW();
- return -EIO;
- done:
- return 0;
- }
- void usb_mass_storage_thread(void *p1, void *p2, void *p3)
- {
- u32_t sectors, len, len_ping, len_pong, disk_left;
- u8_t *page_disk, *page_usb;
- u8_t skip_disk_write;
- u8_t disk_state;
- int ret;
- ARG_UNUSED(p1);
- ARG_UNUSED(p2);
- ARG_UNUSED(p3);
- while (msc_state_running()) {
- restart:
- k_sem_take(&disk_wait_sem, K_FOREVER);
- if (!msc_state_running()) {
- LOG_ERR("msc_state_NOT_running");
- break;
- }
- LOG_DBG("thread_op %d\n", thread_op);
- switch (thread_op) {
- case THREAD_OP_READ_QUEUED:
- usb_rw_working = 0;
- page_disk = page;
- while (length) {
- if (length > page_size) {
- len = page_size;
- } else {
- len = length;
- }
- if ((addr + len) > memory_size) {
- len = memory_size - addr;
- stage = ERROR;
- }
- sectors = len / BLOCK_SIZE;
- LOG_DBG("read %d sectors", sectors);
- #ifdef CONFIG_SPINAND_ACTS
- u32_t offset = get_udisk_offset();
- if (offset != 0) {
- if (flash_read(flash_dev, (addr+offset), page_disk, sectors<<9)) {
- if (disk_ioctl(disk_pdrv, DISK_HW_DETECT, &disk_state) ||
- (disk_state != STA_DISK_OK)) {
- disk_pdrv = MSC_DISK_NO_MEDIA;
- }
- msc_sense_data = SS_UNRECOVERED_READ_ERROR;
- LOG_ERR("Flash Read Error 0x%x %d",
- (u32_t)((addr+offset)/BLOCK_SIZE), sectors);
- break;
- }
- }
- #else
- if (disk_read(disk_pdrv, page_disk, (addr/BLOCK_SIZE), sectors)) {
- if (disk_ioctl(disk_pdrv, DISK_HW_DETECT, &disk_state) ||
- (disk_state != STA_DISK_OK)) {
- disk_pdrv = MSC_DISK_NO_MEDIA;
- }
- msc_sense_data = SS_UNRECOVERED_READ_ERROR;
- LOG_ERR("Disk Read Error 0x%x %d",
- (u32_t)(addr/BLOCK_SIZE), sectors);
- break;
- }
- #endif
- addr += len;
- length -= len;
- csw.DataResidue -= len;
- while (usb_rw_working) {
- ret = k_sem_take(&usb_wait_sem, USB_RW_TIMEOUT);
- if (ret != 0) {
- LOG_ERR("usb write %d", ret);
- goto restart;
- }
- if (!msc_state_running()) {
- goto exit;
- }
- }
- usb_rw_working = 1;
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- if (usb_mass_transfer(page_disk, len) != 0) {
- LOG_ERR("Failed to write EP 0x%x",
- mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- }
- #else
- if (usb_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
- page_disk, len, NULL) != 0) {
- LOG_ERR("Failed to write EP 0x%x",
- mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- }
- #endif
- if (page_disk == page) {
- page_disk = page2;
- } else {
- page_disk = page;
- }
- if (stage == ERROR) {
- break;
- }
- }
- while (usb_rw_working) {
- ret = k_sem_take(&usb_wait_sem, USB_RW_TIMEOUT);
- if (ret != 0) {
- LOG_ERR("usb write last %d", ret);
- goto restart;
- }
- if (!msc_state_running()) {
- goto exit;
- }
- }
- /* stall unitl USB write done */
- if (msc_sense_data) {
- stage = ERROR;
- usb_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
- }
- thread_op = THREAD_OP_READ_DONE;
- csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
- handle_csw();
- break;
- case THREAD_OP_WRITE_QUEUED:
- page_usb = page;
- page_disk = page2;
- disk_left = length;
- skip_disk_write = 0;
- LOG_DBG("length: %d, disk_left: %d",
- length, disk_left);
- if (length > page_size) {
- len_ping = page_size;
- } else {
- len_ping = length;
- }
- length -= len_ping;
- len_pong = 0; /* for compiler */
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- usb_mass_transfer(page_usb, len_ping);
- #else
- usb_read_async(mass_ep_data[MSD_OUT_EP_IDX].ep_addr,
- page_usb, len_ping, NULL);
- #endif
- ret = k_sem_take(&usb_wait_sem, USB_RW_TIMEOUT);
- if (ret != 0) {
- LOG_ERR("usb read first %d", ret);
- goto restart;
- }
- if (!msc_state_running()) {
- goto exit;
- }
- LOG_DBG("usb read ping");
- while (1) {
- while (usb_rw_working) {
- ret = k_sem_take(&usb_wait_sem, USB_RW_TIMEOUT);
- if (ret != 0) {
- LOG_ERR("usb read %d", ret);
- goto restart;
- }
- if (!msc_state_running()) {
- goto exit;
- }
- }
- if (length) {
- usb_rw_working = 1;
- if (length > page_size) {
- len = page_size;
- } else {
- len = length;
- }
- length -= len;
- if (page_usb == page) {
- page_usb = page2;
- len_pong = len;
- LOG_DBG("usb read pong");
- } else {
- page_usb = page;
- len_ping = len;
- LOG_DBG("usb read ping");
- }
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- usb_mass_transfer(page_usb, len);
- #else
- usb_read_async(mass_ep_data[MSD_OUT_EP_IDX].ep_addr,
- page_usb, len, NULL);
- #endif
- }
- if (page_disk == page) {
- page_disk = page2;
- len = len_pong;
- LOG_DBG("disk write pong");
- } else {
- page_disk = page;
- len = len_ping;
- LOG_DBG("disk write ping");
- }
- if ((addr + len) > memory_size) {
- len = memory_size - addr;
- stage = ERROR;
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- LOG_WRN("Stall OUT endpoint");
- }
- sectors = len / BLOCK_SIZE;
- LOG_DBG("write %d sectors\n", sectors);
- #ifdef CONFIG_SPINAND_ACTS
- u32_t offset = get_udisk_offset();
- if (offset != 0) {
- if ((skip_disk_write == 0) &&
- flash_write(flash_dev, (addr+offset), page_disk, sectors<<9)) {
- if (disk_ioctl(disk_pdrv, DISK_HW_DETECT, &disk_state) ||
- (disk_state != STA_DISK_OK)) {
- disk_pdrv = MSC_DISK_NO_MEDIA;
- }
- msc_sense_data = SS_WRITE_ERROR;
- #if DISK_WRITE_ERROR_CONTINUE
- skip_disk_write = 1;
- #else
- stage = ERROR;
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- #endif
- LOG_ERR("Flash Write Error 0x%x %d",
- (u32_t)((addr+offset)/BLOCK_SIZE), sectors);
- }
- }
- #else
- if ((skip_disk_write == 0) &&
- disk_write(disk_pdrv, page_disk, (addr/BLOCK_SIZE), sectors)) {
- if (disk_ioctl(disk_pdrv, DISK_HW_DETECT, &disk_state) ||
- (disk_state != STA_DISK_OK)) {
- disk_pdrv = MSC_DISK_NO_MEDIA;
- }
- msc_sense_data = SS_WRITE_ERROR;
- #if DISK_WRITE_ERROR_CONTINUE
- skip_disk_write = 1;
- #else
- stage = ERROR;
- usb_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
- #endif
- LOG_ERR("Disk Write Error 0x%x %d",
- (u32_t)(addr/BLOCK_SIZE), sectors);
- }
- #endif
- disk_left -= len;
- addr += len;
- csw.DataResidue -= len;
- LOG_DBG("wrote %d, left %d", len, disk_left);
- if ((!disk_left) || (stage != PROCESS_CBW)) {
- #if DISK_WRITE_ERROR_CONTINUE
- if (skip_disk_write) {
- stage = ERROR;
- }
- #endif
- thread_op = THREAD_OP_WRITE_DONE;
- LOG_DBG("write done");
- csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
- sendCSW();
- break;
- }
- }
- break;
- default:
- LOG_ERR("thread_op %d", thread_op);
- }
- }
- exit:
- msc_state_set_aborted();
- }
- /**
- * @brief Initialize USB mass storage setup
- *
- * This routine is called to reset the USB device controller chip to a
- * quiescent state. Also it initializes the backing storage and initializes
- * the mass storage protocol state.
- *
- * @param disk_no MSC_DISK_XXX.
- *
- * @return negative errno code on fatal failure, 0 otherwise
- */
- static int mass_storage_init(u8_t disk_no)
- {
- u32_t block_size = 0;
- u64_t tmp;
- int ret;
- disk_pdrv = disk_no;
- switch_to_stub = 0;
- thread_op = 0;
- msd_state_machine_reset();
- msd_init();
- #ifdef CONFIG_SPINAND_ACTS
- flash_dev =
- device_get_binding("spinand");
- if (!flash_dev) {
- LOG_ERR("spinand flash dev error\n");
- goto error;
- }
- #endif
- ret = disk_initialize(disk_no);
- if (ret) {
- LOG_ERR("no lun/media: %d", disk_no);
- goto error;
- }
- ret = disk_ioctl(disk_no, GET_SECTOR_COUNT, &block_count);
- if (ret) {
- LOG_ERR("Unable to get sector count");
- goto error;
- }
- ret = disk_ioctl(disk_no, GET_BLOCK_SIZE, &block_size);
- if (ret) {
- LOG_ERR("Unable to get block size");
- goto error;
- }
- if (block_size != BLOCK_SIZE) {
- LOG_ERR("block_size: %d", block_size);
- goto error;
- }
- tmp = block_count;
- LOG_WRN("Sect Count %d\n", block_count);
- memory_size = tmp * BLOCK_SIZE;
- LOG_WRN("Memory Size 0x%x%x\n", (u32_t)(memory_size >> 32),
- (u32_t)(memory_size & 0xffffffff));
- return 0;
- error:
- if (disk_no != MSC_DISK_NO_LUN) {
- disk_pdrv = MSC_DISK_NO_MEDIA;
- }
- return -ENODEV;
- }
- /*
- * API: whether USB mass storage is working (reading/writing)
- */
- bool usb_mass_storage_working(void)
- {
- if (!msc_state_running()) {
- return false;
- }
- if ((thread_op == THREAD_OP_READ_QUEUED) ||
- (thread_op == THREAD_OP_WRITE_QUEUED)) {
- return true;
- }
- return false;
- }
- /*
- * API: whether USB mass storage is reading
- */
- bool usb_mass_storage_reading(void)
- {
- if (!msc_state_running()) {
- return false;
- }
- if (thread_op == THREAD_OP_READ_QUEUED) {
- return true;
- }
- return false;
- }
- /*
- * API: whether USB mass storage is writing
- */
- bool usb_mass_storage_writing(void)
- {
- if (!msc_state_running()) {
- return false;
- }
- if (thread_op == THREAD_OP_WRITE_QUEUED) {
- return true;
- }
- return false;
- }
- /*
- * API: add lun/disk for USB mass storage
- */
- int usb_mass_storage_add_lun(u8_t disk_no)
- {
- /* make sure no lun exist */
- if (disk_pdrv < MSC_DISK_NUM) {
- LOG_ERR("%d exist", disk_pdrv);
- return -EBUSY;
- }
- /* make sure new lun is valid */
- if (disk_no >= MSC_DISK_NUM) {
- LOG_ERR("%d invalid", disk_no);
- return -EINVAL;
- }
- if (disk_pdrv == MSC_DISK_NO_MEDIA) {
- msc_sense_data = SS_NOT_READY_TO_READY_TRANSITION;
- } else if (disk_pdrv == MSC_DISK_NO_LUN) {
- msc_sense_data = SS_NO_SENSE;
- }
- mass_storage_init(disk_no);
- LOG_INF("%d, %d", disk_pdrv, disk_no);
- return 0;
- }
- /*
- * API: remove lun/disk for USB mass storage
- */
- int usb_mass_storage_remove_lun(void)
- {
- /* make sure current lun is valid */
- if ((disk_pdrv == MSC_DISK_NO_LUN) ||
- (disk_pdrv == MSC_DISK_NO_MEDIA)) {
- LOG_WRN("already");
- return -EALREADY;
- }
- disk_pdrv = MSC_DISK_NO_MEDIA;
- LOG_INF("done");
- return 0;
- }
- /*
- * API: register disk eject callback for USB mass storage
- */
- void usb_mass_storage_register_eject_cb(usb_msc_eject_callback cb)
- {
- eject_cb = cb;
- }
- /*
- * API: register disk for USB mass storage
- */
- void usb_mass_storage_register(u8_t disk_no)
- {
- /* make sure new lun is valid */
- if (disk_no >= MSC_DISK_NUM) {
- LOG_ERR("%d invalid", disk_no);
- disk_pdrv = MSC_DISK_NO_LUN;
- } else {
- disk_pdrv = disk_no;
- }
- LOG_INF("%d", disk_pdrv);
- }
- /*
- * API: initialize USB mass storage
- */
- int usb_mass_storage_init(struct device *dev, u8_t *buf, u32_t len)
- {
- int ret;
- ARG_UNUSED(dev);
- if (!buf || !len) {
- LOG_ERR("param is null");
- return ERROR;
- }
- if ((long)buf & 0x3) {
- LOG_ERR("4-byte alignment required!");
- return ERROR;
- }
- if (len % (BLOCK_SIZE * 2)) {
- LOG_ERR("illegal buff len");
- return ERROR;
- }
- page_size = len/2;
- page = buf;
- page2 = buf + page_size;
- if (!msc_state_unknown()) {
- LOG_ERR("state: %d", msc_state);
- return 0;
- }
- msc_sense_data = SS_NO_SENSE;
- /* for example: eject -> exit -> init */
- if (disk_pdrv == MSC_DISK_NO_MEDIA) {
- disk_pdrv = CONFIG_MASS_STORAGE_DISK_PDRV;
- }
- mass_storage_init(disk_pdrv);
- /* Register string descriptor */
- ret = usb_device_register_string_descriptor(MANUFACTURE_STR_DESC,
- CONFIG_MASS_STORAGE_MANUFACTURER,
- strlen(CONFIG_MASS_STORAGE_MANUFACTURER));
- if (ret) {
- return ret;
- }
- ret = usb_device_register_string_descriptor(PRODUCT_STR_DESC,
- CONFIG_MASS_STORAGE_PRODUCT,
- strlen(CONFIG_MASS_STORAGE_PRODUCT));
- if (ret) {
- return ret;
- }
- ret = usb_device_register_string_descriptor(DEV_SN_DESC,
- CONFIG_MASS_STORAGE_SN,
- strlen(CONFIG_MASS_STORAGE_SN));
- if (ret) {
- return ret;
- }
- /* Register device descriptor */
- usb_device_register_descriptors(mass_storage_fs_descriptor,
- mass_storage_hs_descriptor);
- /* Initialize the USB driver with the right configuration */
- ret = usb_set_config(&mass_storage_config);
- if (ret < 0) {
- LOG_ERR("Failed to config USB");
- return ret;
- }
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- usb_dc_ep_set_multi_fifo(CONFIG_MASS_STORAGE_OUT_EP_ADDR);
- usb_dc_ep_set_multi_fifo(CONFIG_MASS_STORAGE_IN_EP_ADDR);
- #endif
- /* Enable USB driver */
- ret = usb_enable(&mass_storage_config);
- if (ret < 0) {
- LOG_ERR("Failed to enable USB");
- return ret;
- }
- k_sem_init(&disk_wait_sem, 0, 1);
- k_sem_init(&usb_wait_sem, 0, 1);
- #ifdef CONFIG_MASS_STORAGE_SWITCH_TO_ADFU
- k_work_init(&switch_to_adfu_work, switch_to_adfu_work_handler);
- #endif
- k_work_init(&disk_sync_work, disk_sync_work_handler);
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- k_delayed_work_init(&usb_mass_transfer_work, usb_mass_transfer_handler);
- #endif
- msc_state_set_running();
- #ifndef CONFIG_USB_MASS_STORAGE_SHARE_THREAD
- /* Start a thread to offload disk ops */
- k_thread_create(&mass_thread_data, mass_thread_stack,
- DISK_THREAD_STACK_SZ,
- usb_mass_storage_thread, NULL, NULL, NULL,
- DISK_THREAD_PRIO, 0, K_NO_WAIT);
- #endif
- return 0;
- }
- /*
- * API: deinitialize USB mass storage synchronously
- */
- int usb_mass_storage_exit(void)
- {
- int ret;
- if (!msc_state_running()) {
- LOG_ERR("state: %d", msc_state);
- return 0;
- }
- LOG_INF("");
- msc_state_clear_running();
- k_sem_give(&disk_wait_sem);
- k_sem_give(&usb_wait_sem);
- #ifdef CONFIG_USB_AOTG_DC_MULTI_FIFO
- usb_dc_ep_io_cancel();
- k_delayed_work_cancel(&usb_mass_transfer_work);
- #endif
- /* wait for completion */
- while (!msc_state_aborted()) {
- k_sleep(K_MSEC(10));
- }
- disk_ioctl(disk_pdrv, CTRL_SYNC, NULL);
- eject_cb = NULL; /* Disk may be changed */
- msc_state_set_unknown();
- page = NULL;
- page2 = NULL;
- ret = usb_disable();
- if (ret) {
- LOG_ERR("Failed to disable USB: %d", ret);
- return ret;
- }
- usb_deconfig();
- LOG_INF("done");
- return 0;
- }
- /*
- * API: whether USB mass storage is ejected
- */
- bool usb_mass_storage_ejected(void)
- {
- return msc_state_ejected();
- }
- /*
- * API: whether USB mass storage is enabled
- */
- bool usb_mass_storage_enabled(void)
- {
- return msc_state_running();
- }
- /*
- * API: whether USB mass storage is switched to stub
- */
- bool usb_mass_storage_stub_mode(void)
- {
- return msc_state_running() && (switch_to_stub == SWITCH_TO_STUB_DONE);
- }
- /*
- * API: start USB mass storage after initializing
- */
- int __weak usb_mass_storage_start(void)
- {
- LOG_INF("weak");
- return 0;
- }
|