mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			317 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			317 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
/*
 | 
						|
 * Copyright (c) 2018-2019, Arm Limited and affiliates.
 | 
						|
 * SPDX-License-Identifier: Apache-2.0
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef USBMSD_H
 | 
						|
#define USBMSD_H
 | 
						|
 | 
						|
/* These headers are included for child class. */
 | 
						|
#include "USBDescriptor.h"
 | 
						|
#include "USBDevice_Types.h"
 | 
						|
#include "platform/Callback.h"
 | 
						|
#include "drivers/internal/PolledQueue.h"
 | 
						|
#include "drivers/internal/Task.h"
 | 
						|
#include "BlockDevice.h"
 | 
						|
#include "Mutex.h"
 | 
						|
 | 
						|
#include "USBDevice.h"
 | 
						|
 | 
						|
/**
 | 
						|
 * \defgroup drivers_USBMSD USBMSD class
 | 
						|
 * \ingroup drivers-public-api-usb
 | 
						|
 * @{
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * USBMSD class: generic class in order to use all kinds of blocks storage chip
 | 
						|
 *
 | 
						|
 * Introduction
 | 
						|
 *
 | 
						|
 * USBMSD implements the MSD protocol. It permits to access a block device (flash, SD Card,...)
 | 
						|
 * from a computer over USB.
 | 
						|
 *
 | 
						|
 * @code
 | 
						|
 * #include "mbed.h"
 | 
						|
 * #include "SDBlockDevice.h"
 | 
						|
 * #include "USBMSD.h"
 | 
						|
 *
 | 
						|
 * SDBlockDevice sd(PTE3, PTE1, PTE2, PTE4);
 | 
						|
 * USBMSD usb(&sd);
 | 
						|
 *
 | 
						|
 * int main() {
 | 
						|
 *
 | 
						|
 *     while(true) {
 | 
						|
 *         usb.process();
 | 
						|
 *     }
 | 
						|
 *
 | 
						|
 *     return 0;
 | 
						|
 * }
 | 
						|
 * @endcode
 | 
						|
 */
 | 
						|
class USBMSD: public USBDevice {
 | 
						|
public:
 | 
						|
 | 
						|
    /**
 | 
						|
    * Constructor
 | 
						|
    *
 | 
						|
    * This creates a new USBMSD object with the given block device. Connect must be called
 | 
						|
    * for the block device to connect.
 | 
						|
    *
 | 
						|
    * @param bd BlockDevice to mount as a USB drive
 | 
						|
    * @param connect_blocking true to perform a blocking connect, false to start in a disconnected state
 | 
						|
    * @param vendor_id Your vendor_id
 | 
						|
    * @param product_id Your product_id
 | 
						|
    * @param product_release Your preoduct_release
 | 
						|
    */
 | 
						|
    USBMSD(BlockDevice *bd, bool connect_blocking = true, uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001);
 | 
						|
 | 
						|
    /**
 | 
						|
    * Fully featured constructor
 | 
						|
    *
 | 
						|
    * Construct this object with the supplied USBPhy and parameters. The user
 | 
						|
    * this object is responsible for calling connect() or init().
 | 
						|
    *
 | 
						|
    * @note Derived classes must use this constructor and call init() or
 | 
						|
    * connect() themselves. Derived classes should also call deinit() in
 | 
						|
    * their destructor. This ensures that no interrupts can occur when the
 | 
						|
    * object is partially constructed or destroyed.
 | 
						|
    *
 | 
						|
    * @param phy USB phy to use
 | 
						|
    * @param bd BlockDevice to mount as a USB drive
 | 
						|
    * @param vendor_id Your vendor_id
 | 
						|
    * @param product_id Your product_id
 | 
						|
    * @param product_release Your preoduct_release
 | 
						|
    */
 | 
						|
    USBMSD(USBPhy *phy, BlockDevice *bd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
 | 
						|
 | 
						|
    /**
 | 
						|
     * Destroy this object
 | 
						|
     *
 | 
						|
     * Any classes which inherit from this class must call disconnect
 | 
						|
     * before this destructor runs.
 | 
						|
     */
 | 
						|
    virtual ~USBMSD();
 | 
						|
 | 
						|
    /**
 | 
						|
    * Connect the USB MSD device.
 | 
						|
    *
 | 
						|
    * @returns true if successful
 | 
						|
    */
 | 
						|
    bool connect();
 | 
						|
 | 
						|
    /**
 | 
						|
    * Disconnect the USB MSD device.
 | 
						|
    */
 | 
						|
    void disconnect();
 | 
						|
 | 
						|
    /**
 | 
						|
    * Perform USB processing
 | 
						|
    */
 | 
						|
    void process();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Called when USBMSD needs to perform processing
 | 
						|
     *
 | 
						|
     * @param cb Callback called when USBMSD needs process() to be called
 | 
						|
     */
 | 
						|
    void attach(mbed::Callback<void()> cb);
 | 
						|
 | 
						|
    /**
 | 
						|
    * Check if MSD device was removed/unmounted on the host side.
 | 
						|
    *
 | 
						|
    * @returns true if device was removed/unmounted on the host side
 | 
						|
    */
 | 
						|
    bool media_removed();
 | 
						|
 | 
						|
protected:
 | 
						|
 | 
						|
    /*
 | 
						|
    * read one or more blocks on a storage chip
 | 
						|
    *
 | 
						|
    * @param data pointer where will be stored read data
 | 
						|
    * @param block starting block number
 | 
						|
    * @param count number of blocks to read
 | 
						|
    * @returns 0 if successful
 | 
						|
    */
 | 
						|
    virtual int disk_read(uint8_t *data, uint64_t block, uint8_t count);
 | 
						|
 | 
						|
    /*
 | 
						|
    * write one or more blocks on a storage chip
 | 
						|
    *
 | 
						|
    * @param data data to write
 | 
						|
    * @param block starting block number
 | 
						|
    * @param count number of blocks to write
 | 
						|
    * @returns 0 if successful
 | 
						|
    */
 | 
						|
    virtual int disk_write(const uint8_t *data, uint64_t block, uint8_t count);
 | 
						|
 | 
						|
    /*
 | 
						|
    * Disk initilization
 | 
						|
    */
 | 
						|
    virtual int disk_initialize();
 | 
						|
 | 
						|
    /*
 | 
						|
    * Return the number of blocks
 | 
						|
    *
 | 
						|
    * @returns number of blocks
 | 
						|
    */
 | 
						|
    virtual uint64_t disk_sectors();
 | 
						|
 | 
						|
    /*
 | 
						|
    * Return memory size
 | 
						|
    *
 | 
						|
    * @returns memory size
 | 
						|
    */
 | 
						|
    virtual uint64_t disk_size();
 | 
						|
 | 
						|
    /*
 | 
						|
    * To check the status of the storage chip
 | 
						|
    *
 | 
						|
    * @returns status: 0: OK, 1: disk not initialized, 2: no medium in the drive, 4: write protected
 | 
						|
    */
 | 
						|
    virtual int disk_status();
 | 
						|
 | 
						|
private:
 | 
						|
 | 
						|
    // MSC Bulk-only Stage
 | 
						|
    enum Stage {
 | 
						|
        READ_CBW,     // wait a CBW
 | 
						|
        ERROR,        // error
 | 
						|
        PROCESS_CBW,  // process a CBW request
 | 
						|
        SEND_CSW,     // send a CSW
 | 
						|
    };
 | 
						|
 | 
						|
    // Bulk-only CBW
 | 
						|
    typedef MBED_PACKED(struct)
 | 
						|
    {
 | 
						|
        uint32_t Signature;
 | 
						|
        uint32_t Tag;
 | 
						|
        uint32_t DataLength;
 | 
						|
        uint8_t  Flags;
 | 
						|
        uint8_t  LUN;
 | 
						|
        uint8_t  CBLength;
 | 
						|
        uint8_t  CB[16];
 | 
						|
    } CBW;
 | 
						|
 | 
						|
    // Bulk-only CSW
 | 
						|
    typedef MBED_PACKED(struct)
 | 
						|
    {
 | 
						|
        uint32_t Signature;
 | 
						|
        uint32_t Tag;
 | 
						|
        uint32_t DataResidue;
 | 
						|
        uint8_t  Status;
 | 
						|
    } CSW;
 | 
						|
 | 
						|
    // If this class has been initialized
 | 
						|
    bool _initialized;
 | 
						|
 | 
						|
    // If msd device has been unmounted by host
 | 
						|
    volatile bool _media_removed;
 | 
						|
 | 
						|
    //state of the bulk-only state machine
 | 
						|
    Stage _stage;
 | 
						|
 | 
						|
    // current CBW
 | 
						|
    CBW _cbw;
 | 
						|
 | 
						|
    // CSW which will be sent
 | 
						|
    CSW _csw;
 | 
						|
 | 
						|
    // addr where will be read or written data
 | 
						|
    uint32_t _addr;
 | 
						|
 | 
						|
    // length of a reading or writing
 | 
						|
    uint32_t _length;
 | 
						|
 | 
						|
    // memory OK (after a memoryVerify)
 | 
						|
    bool _mem_ok;
 | 
						|
 | 
						|
    // cache in RAM before writing in memory. Useful also to read a block.
 | 
						|
    uint8_t *_page;
 | 
						|
 | 
						|
    int _block_size;
 | 
						|
    uint64_t _memory_size;
 | 
						|
    uint64_t _block_count;
 | 
						|
 | 
						|
    // endpoints
 | 
						|
    usb_ep_t _bulk_in;
 | 
						|
    usb_ep_t _bulk_out;
 | 
						|
    uint8_t _bulk_in_buf[64];
 | 
						|
    uint8_t _bulk_out_buf[64];
 | 
						|
    bool _out_ready;
 | 
						|
    bool _in_ready;
 | 
						|
    uint32_t _bulk_out_size;
 | 
						|
 | 
						|
    // Interrupt to thread deferral
 | 
						|
    events::PolledQueue _queue;
 | 
						|
    events::Task<void()> _in_task;
 | 
						|
    events::Task<void()> _out_task;
 | 
						|
    events::Task<void()> _reset_task;
 | 
						|
    events::Task<void(const setup_packet_t *)> _control_task;
 | 
						|
    events::Task<void()> _configure_task;
 | 
						|
 | 
						|
    BlockDevice *_bd;
 | 
						|
    rtos::Mutex _mutex_init;
 | 
						|
    rtos::Mutex _mutex;
 | 
						|
 | 
						|
    // space for config descriptor
 | 
						|
    uint8_t _configuration_descriptor[32];
 | 
						|
 | 
						|
    virtual const uint8_t *string_iproduct_desc();
 | 
						|
    virtual const uint8_t *string_iinterface_desc();
 | 
						|
    virtual const uint8_t *configuration_desc(uint8_t index);
 | 
						|
    virtual void callback_set_configuration(uint8_t configuration);
 | 
						|
    virtual void callback_set_interface(uint16_t interface, uint8_t alternate);
 | 
						|
    virtual void callback_state_change(DeviceState new_state);
 | 
						|
    virtual void callback_request(const setup_packet_t *setup);
 | 
						|
    virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted);
 | 
						|
 | 
						|
    void _isr_out();
 | 
						|
    void _isr_in();
 | 
						|
 | 
						|
    void _out();
 | 
						|
    void _in();
 | 
						|
    void _reset();
 | 
						|
    void _control(const setup_packet_t *request);
 | 
						|
    void _configure();
 | 
						|
 | 
						|
    void _init();
 | 
						|
    void _process();
 | 
						|
    void _write_next(uint8_t *data, uint32_t size);
 | 
						|
    void _read_next();
 | 
						|
 | 
						|
    void CBWDecode(uint8_t *buf, uint16_t size);
 | 
						|
    void sendCSW(void);
 | 
						|
    bool inquiryRequest(void);
 | 
						|
    bool write(uint8_t *buf, uint16_t size);
 | 
						|
    bool readFormatCapacity();
 | 
						|
    bool readCapacity(void);
 | 
						|
    bool infoTransfer(void);
 | 
						|
    void memoryRead(void);
 | 
						|
    bool modeSense6(void);
 | 
						|
    bool modeSense10(void);
 | 
						|
    void testUnitReady(void);
 | 
						|
    bool requestSense(void);
 | 
						|
    void memoryVerify(uint8_t *buf, uint16_t size);
 | 
						|
    void memoryWrite(uint8_t *buf, uint16_t size);
 | 
						|
    void msd_reset();
 | 
						|
    void fail();
 | 
						|
};
 | 
						|
 | 
						|
/** @}*/
 | 
						|
 | 
						|
#endif
 |