📄 massstorage.dir
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
/// \dir
///
/// !!!Purpose
///
/// This directory provides definitions, structs and functions for a USB Mass
/// Storage %device (MSD) - USB Mass Storage demo.
///
/// !!!Contents
///
/// There are four things for the implement of the USB MSD driver:
/// - Implement the MSD driver structs and functions for the %device,
/// to initialize, to handle MSD-specific requests and dispach
/// standard requests in USBD callbacks, to read/write through assigned USB
/// %endpoints,
/// - Create the MSD device's descriptors that should be passed to
/// the USBDDriver instance on initialization, so that the host can
/// recognize the %device as a USB Mass Storage %device.
/// - Implement state machine for MSD command/data/status handling.
/// - Implement storage media interface for MSD disk accessing.
///
/// For more information about what a particular group contains, please refer to
/// "USB MSD Driver".
//------------------------------------------------------------------------------
/**
\page "USB MSD Driver"
This page describes how to use the USB framework to produce a USB MSD driver,
which appears as a USB Disk on host.
!!!References
- "AT91 USB device framework"
- "USB Device Enumeration"
- <a href="http://www.usb.org/developers/docs/usb_20_040908.zip">
Universal Serial Bus Revision 2.0 specification
</a> (.zip file format, size 9.80 MB)
- <a href="http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf">
Mass Storage Overview 1.2</a>
- <a href="http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf">
Mass Storage Bulk Only 1.0</a>
- <a href="http://www.t10.org/scsi-3.htm">SCSI Standards</a>
- SCSI Block Commands - 3 (SBC-3)
- SCSI Primary Commands - 4 (SPC-4)
!!!Mass Storage Class Basic
This section gives generic details on the MSD class.
See "USB MSD Basic".
!!!Mass Storage SCSI Disk
This section describes how to implement a USB disk by using the MSD class with
the SCSI transparent command set and the AT91 USB Framework. For more
information about the framework, please refer to the "AT91 USB device
framework" application note; details about the USB and the Mass Storage class
can be found in the USB specification 2.0 and the MSC Bulk-Only Transport
specification 1.0 documents, respectively.
The software example provided with this document uses the ram disk of the chip
as its storage medium, but has been designed in a modular way to allow easy
modification for any medium, e.g. internal flash, DataFlash, SD card, external
Flash chip.
!!Architecture
The MSD driver is based on framework, See "USB Device Framework Architecture".
The internal architecture of the Application layer is extended for the
following factors:
- The Command/Data/Status flow described in "USB MSD Basic" requires the use
of a #state machine# for non-blocking operation.
- The example software has been designed to be easily extended with support
for other media.
- The example software has been designed to support multiple LUNs on one or
more media.
\image MSDAppArch.png "Application Layer Architecture"
!!Descriptors
There are no class-specific descriptors for a device using the MSD class with
the Bulk-only transport protocol. This section thus only details the values
which must be set in the standard descriptors.
!Device Descriptor
\code
static const USBDeviceDescriptor deviceDescriptor = {
sizeof(USBDeviceDescriptor), // bLength: Size of descriptor (18 bytes)
USBGenericDescriptor_DEVICE, // bDescriptorType: Device descriptor
USBDeviceDescriptor_USB2_00, // bcdUSB: USB 2.00
MSDeviceDescriptor_CLASS, // bDeviceClass: 0
MSDeviceDescriptor_SUBCLASS, // bDeviceSubClass: 0
MSDeviceDescriptor_PROTOCOL, // bDeviceProtocol: 0
BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), // bMaxPacketSize0: Max Size EP0
MSDDriverDescriptors_VENDORID, // idVendor: Vendor ID ATMEL (0x03eb)
MSDDriverDescriptors_PRODUCTID,// idProduct: Product ID (0x6202)
MSDDriverDescriptors_RELEASE, // bcdDevice: 0x0001, Version 0.01
1, // iManufacturer: Manufacturer string (manufacturerDescriptor) index.
2, // iProduct: Product string (productDescriptor) index.
3, // iSerialNumber: Serial number string (serialNumberDescriptor) index.
1 // bNumConfigurations: Device has one possible configuration.
};
\endcode
Note that the Vendor ID is a special value attributed by the USB-IF
organization. The product ID can be chosen freely by the vendor.
!Configuration Descriptor
The descriptors are defined as:
\code
const MSDConfigurationDescriptors configurationDescriptorsFS;
\endcode
Configuration descriptor
\code
// Standard configuration descriptor.
{
sizeof(USBConfigurationDescriptor), // bLength: 9 bytes
USBGenericDescriptor_CONFIGURATION, // bDescriptorType: Configuration
sizeof(MSDConfigurationDescriptors),// wTotalLength: Length of all
1, // bNumInterface: Configuration has one interface.
1, // bConfigurationValue: This is configuration #1.
0, // iConfiguration: No string descriptor for configuration.
BOARD_USB_BMATTRIBUTES, // bmAttributes: Power and remote wakeup
USBConfigurationDescriptor_POWER(100) // 100mA max power
},
\endcode
!Interface Descriptor
The interface descriptor must indicate several features:
- #Mass Storage Device# class code (08h) in the }bInterfaceClass} field
- #Data Transport Protocol# code in the }bInterfaceSubclass} field
- #Bulk-Only Transport# protocol code (50h) in the }bInterfaceProtocol} field
This example uses the SCSI transparent command set (code 06h). This is the
most appropriate setting for a Flash %device, given that the RBC command set
is not supported by Microsoft Windows.
\code
// Mass Storage interface descriptor.
{
sizeof(USBInterfaceDescriptor), // bLength: Size of descriptor(9 bytes)
USBGenericDescriptor_INTERFACE, // bDescriptorType: Interface descriptor
0, // bInterfaceNumber: This is interface #0.
0, // bAlternateSetting: This is alternate setting #0.
2, // bNumEndpoints: Interface uses two endpoints.
MSInterfaceDescriptor_CLASS, // bInterfaceClass: Mass Storage Device Class
MSInterfaceDescriptor_SCSI, // bInterfaceSubClass: SCSI transparent command
MSInterfaceDescriptor_BULKONLY,// bInterfaceProtocol: Bulk-Only transport
0 // iInterface: No string descriptor for interface.
},
\endcode
!Endpoint Descriptors
No special requirements on these apart from being Bulk-IN and Bulk-OUT.
\code
// Bulk-OUT endpoint descriptor
{
sizeof(USBEndpointDescriptor), // bLength: 7 bytes
USBGenericDescriptor_ENDPOINT, // bDescriptorType: Endpoint descriptor
USBEndpointDescriptor_ADDRESS(
USBEndpointDescriptor_OUT,
MSDDriverDescriptors_BULKOUT), // bEndpointAddress: OUT 0x01
USBEndpointDescriptor_BULK, // bmAttributes: Bulk endpoint
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKOUT),
USBEndpointDescriptor_MAXBULKSIZE_FS), // wMaxPacketSize: 64 bytes
0 // bInterval: Must be 0 for full-speed Bulk endpoints.
},
// Bulk-IN endpoint descriptor
{
sizeof(USBEndpointDescriptor), // bLength: 7 bytes
USBGenericDescriptor_ENDPOINT, // bDescriptorType: Endpoint descriptor
USBEndpointDescriptor_ADDRESS(
USBEndpointDescriptor_IN,
MSDDriverDescriptors_BULKIN), // bEndpointAddress: IN 0x82
USBEndpointDescriptor_BULK, // bmAttributes: Bulk endpoint
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKIN),
USBEndpointDescriptor_MAXBULKSIZE_FS), // wMaxPacketSize: 64
0 // bInterval: Must be 0 for full-speed Bulk endpoints.
}
\endcode
!String descriptors
Several descriptors can be commented with a String descriptor. The latter are
completely optional and do not influence the detection of the device by the
operating system. Whether or not to include them is entirely up to the
programmer.
There is one exception to this rule when using the MSD class. According to the
specification, there must be a Serial Number string. It must contains at least
12 characters, and these characters must only be either letters (a-z, A-Z) or
numbers (0-9). This cause no problem for the driver in practice, but this is a
strict requirement for certification. Also remember that string descriptors
use the Unicode format.
See manufacturerDescriptor, productDescriptor, serialNumberDescriptor.
!!Class-specific Requests
There are two Mass Storage-specific requests:
- GetMaxLUN
- Bulk-Only Mass Storage Reset
Standard requests can be forwarded to the USBDDriver_RequestHandler, with one
exception: #CLEAR_FEATURE#. This is necessary for Reset Recovery sequence.
!ClearFeature
As previously stated, the CLEAR_FEATURE request must be handled in a
particular way, depending on whether or not the device is waiting for a Reset
Recovery sequence. If it is, then CLEAR_FEATURE requests to unhalt a Bulk
endpoint must be discarded.
In the example software, this behavior is indicated by a boolean field in the
driver structure, named waitResetRecovery. The handler only has to check this
field value to decide whether to forward the request to the standard handler
or to discard it.
\code
// Handle requests
switch (USBGenericRequest_GetRequest(request)) {
//---------------------
case USBGenericRequest_CLEARFEATURE:
//---------------------
switch (USBFeatureRequest_GetFeatureSelector(request)) {
//---------------------
case USBFeatureRequest_ENDPOINTHALT:
//---------------------
// Do not clear the endpoint halt status if the device is waiting
// for a reset recovery sequence
if (!msdDriver.waitResetRecovery) {
// Forward the request to the standard handler
USBDDriver_RequestHandler(&usbdDriver, request);
}
USBD_Write(0, 0, 0, 0, 0);
break;
//------
default:
//------
// Forward the request to the standard handler
USBDDriver_RequestHandler(&usbdDriver, request);
}
break;
}
\endcode
!GetMaxLUN
Usually, the first request issued by the host right after the enumeration
phase will be a GET_MAX_LUN request. It enables it to discover how many
different logical units the device has; each of these LUNs can then be queried
in turn by the host when needed.
After the request is received by the device, it should return one byte of data
indicating the maximum Logical Unit Number (LUN). It is equal to the number of
LUNs used by the device minus one. For example, a device with three LUNs shall
return a GET_MAX_LUN value of two.
Sending this byte is done by calling the USBD_Write method on Control endpoint
0. Note that the data must be held in a permanent buffer (since the transfer
is asynchronous); in the software provided with this application note, a
dedicated field is used in the driver structure (MSDDriver) to store this
value.
In addition due to the }Mass Storage Bulk-Only Transport} specification the
}wValue} should be 0, }wLength} should be 1, }wIndex} should be the interface
number also 0. A request which does not comply to these requirements must be
STALLed.
\code
//-------------------
case MSD_GET_MAX_LUN:
//-------------------
// Check request parameters
if ((request->wValue == 0)
&& (request->wIndex == 0)
&& (request->wLength == 1)) {
USBD_Write(0, &(msdDriver.maxLun), 1, 0, 0);
}
else {
USBD_Stall(0);
}
break;
\endcode
!Bulk-Only Mass Storage Reset
The host issues #RESET# requests to return the MSD driver of the device to its
initial state, i.e., ready to receive a new command. However, this request
does not impact the USB controller state; in particular, endpoints must not be
reset. This means the data toggle bit must not be altered, and Halted endpoint
must not be returned to a normal state. After processing the reset, the device
must return a Zero-Length Packet (ZLP) to acknowledge the SETUP transfer.
Like GET_MAX_LUN, this request must be issued with specific parameters -
wValue, wIndex and wLength should be zero. A request which does not have valid
values in its field must be acknowledged with a STALL handshake from the
%device.
The handler for this request must return the state machine to its initial state.
\code
//-----------------------
case MSD_BULK_ONLY_RESET:
//-----------------------
// Check parameters
if ((request->wValue == 0)
&& (request->wIndex == 0)
&& (request->wLength == 0)) {
// Reset the MSD driver
MSDDriver_Reset();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -